XPO’dan XML’e: Yapay Zekâ Desteğiyle AX 2009’dan Dynamics 365’e X++ Kod Yükseltme
AX 2009’dan Dynamics 365 Finance & Operations’a geçiş gündeme geldiğinde, üzerinde en çok durduğumuz konulardan biri yıllar içinde yapılan geliştirmelerin nasıl taşınacağı oluyor. Uzun süredir kullanılan bir sistemde tablolar, sınıflar, formlar ve raporlar şirketin iş yapış biçiminin bir parçası haline geliyor. Bu geliştirmelerin hangilerine hâlâ ihtiyaç olduğunu belirlemek, mevcut iş mantığını anlamak ve yeni sürüme uyarlamak geçişin önemli bir bölümünü oluşturuyor.
İki sürüm arasında geliştirme açısından ciddi farklar var. AX 2009’daki bir formun, raporun veya standart nesne üzerinde yapılan değişikliğin Dynamics 365’teki karşılığını bulmak her zaman kolay olmuyor. Bazı yapıları benzer şekilde taşıyabilirken bazılarını yeni platformun sunduğu yöntemlerle yeniden ele almamız gerekiyor. Üstelik kodun derlenmesi de tek başına yeterli değil. Formların, raporların ve iş kurallarının beklediğimiz şekilde çalıştığını kontrol etmemiz gerekiyor.
Peki, yapay zekâyı bu sürecin neresinde kullanabiliriz? X++ kodunu anlamak, nesneler arasındaki bağımlılıkları çıkarmak ve hedef sürüme uygun kod üretmek için nasıl bir çalışma düzeni kurabiliriz? Son dönemde üzerinde çalıştığım konulardan biri bu. Özellikle dönüşüm kurallarını önceden tanımladığımızda ve üretilen sonucu düzenli olarak doğruladığımızda, kod yükseltme sürecinde yapay zekâdan daha sistemli şekilde yararlanabileceğimizi düşünüyorum.
Bu yazıda AX 2009’dan aldığımız XPO dosyalarını başlangıç noktası olarak kullanacağız. Claude Code ile kaynak nesneleri inceleyecek, dönüşüm kurallarını oluşturacak ve Dynamics 365’in kullandığı metadata XML yapısına taşıyacağız. Süreç boyunca hangi değişikliklerin zorunlu olduğunu, hangi noktalarda karar vermemiz gerektiğini ve üretilen nesneleri nasıl kontrol edebileceğimizi ele alacağız. Araç kiralama modülü üzerinden tabloları, formları ve MorphX raporlarının SSRS’e dönüşümünü adım adım inceleyeceğiz.
Burada özellikle önemsediğim konu, yapılan değişikliklerin nedenini takip edebilmek. Bir alanın, metodun veya ilişkinin hedef sürümde nasıl karşılandığını görebilmeliyiz. Kaynak kodda bir hata bulduğumuzda da bunu sürüm geçişi için gereken değişikliklerden ayırabilmeliyiz. Oluşturacağımız kural seti ve karar kayıtları, hem dönüşümü kontrol etmemizi hem de sonraki geliştirmelerde aynı birikimden yararlanmamızı sağlayacak.
Yazının kapsamı uygulama kodunun ve metadata yapısının taşınması olacak. İşlem verilerinin, bakiyelerin ve geçmiş hareketlerin aktarılması ayrı bir çalışma gerektiriyor. Burada kodun analizinden başlayıp hedef ortamda derlenmesine, formların kullanılmasına ve rapor çıktılarının alınmasına kadar uzanan sürece odaklanacağız.
Başlamadan önce
Kod taşıma sürecine geçmeden önce kaynak dosyaları ve hedef geliştirme ortamını hazırlamamız gerekiyor. Yapay zekânın kaynak kodu okuyabilmesi kadar, ürettiği nesneleri hangi yapıya göre oluşturacağını ve nasıl doğrulayacağını bilmesi de önemli. Bu nedenle çalışmaya XPO dosyaları, etiketler, hedef ortamda çalışan örnekler ve derleme araçlarını bir araya getirerek başlayacağız.
Yazı boyunca kullanacağımız temel kavramları da burada kısaca açıklayalım:
Tablo 1. Temel kavramlar
| Kavram | Açıklama |
| XPO | AX 2009’daki AOT nesnelerini kodları ve özellikleriyle birlikte metin olarak dışa aktarabildiğimiz dosya biçimi. Dönüşümün kaynağını bu dosyalar oluşturacak. Orijinal dosyaları koruyup üretilen nesneleri ayrı bir klasörde tutacağız. |
| UDE | Unified developer environment. Unified Development Experience yaklaşımında yerel geliştirme araçlarıyla birlikte kullanılan bulut geliştirme ortamı; üretilen nesnelerin deploy edilmesi ve çalışma zamanı kontrolleri için kullanacağız. |
| xppc | X++ kodunu komut satırından derlememizi sağlayan derleyici. Dönüşüm sırasında hataları daha erken görebilmek için derleme kontrollerini bu araç üzerinden çalıştıracağız. |
| Paket ve model | Dynamics 365’te geliştirmeleri düzenlemek için kullandığımız yapılar. Model, nesneleri ve modele ait bilgileri tanımlar; paket ise derleme ve dağıtım yapısıyla ilişkilidir. Taşıdığımız nesneleri hedef modelin ilgili metadata klasörlerinde oluşturacağız. |
| Overlayering | Standart bir nesne üzerinde doğrudan değişiklik yapılması. Eski sürümlerde bu yöntemle yapılan geliştirmeleri Dynamics 365’e taşırken extension, Chain of Command ve event handler gibi seçeneklerle değerlendirmemiz gerekecek. |
| Form pattern | Formların yapısını ve kontrollerin yerleşimini belirleyen tasarım desenleri. Simple List, Details Master ve Details Transaction bunlara örnek. Kaynak formun kullanımına göre uygun deseni seçerek hedef formu oluşturacağız. |
Başlangıçta dört kaynağı hazır tutacağız: AX 2009 XPO ve etiket dosyaları, kullanıma hazır bir UDE ortamı, aynı ortamda derlenen bir referans model ve Claude Code ile derleme kontrolü betiği. Kaynak dosyaların hazırlanmasını bir sonraki bölümde ayrıntılı olarak ele alacağız.
Hedef tarafta kullanıma hazır bir unified developer environment (UDE) bulunmalı. Bu ortam, Unified Development Experience yaklaşımında yerel geliştirme araçlarının buluttaki Finance and Operations ortamıyla birlikte çalışmasını sağlıyor. Bu çalışmada kullanılan geliştirme paketi sürümü 10.0.2527.116. Metadata yapısını, form pattern’lerini ve standart nesne bağımlılıklarını kendi hedef ortamımıza göre doğrulamamız gerekiyor.
Bir diğer hazırlık, aynı ortamda derlenen ve çalışan bir Dynamics 365 modelini referans olarak belirlemek. Claude Code’a hedef XML yapısını yalnızca tarif etmek yerine, doğru çalışan nesneleri de göstereceğiz. Tablo, form veya sınıf üretirken bu örneklerden yararlanacağız. Referans modelde bulunmayan nesne türleri için hedef sürümdeki standart nesneleri inceleyeceğiz.
Son olarak Claude Code’u ve derleme kontrolünde kullanacağımız betiği hazırlayacağız. Claude Code kaynakları inceleme ve hedef nesneleri üretme işini üstlenirken, betik üzerinden xppc kontrollerini çalıştıracağız. Böylece bütün dönüşümün tamamlanmasını beklemeden, her aşamada oluşan hataları görüp ilgili nesneye veya dönüşüm kuralına geri dönebileceğiz.
XPO ve etiket dosyalarını hazırlamak
İlk olarak taşıyacağımız geliştirmeleri AX 2009’dan dışarı almamız gerekiyor. Bunun için XPO dosyalarını kullanacağız. XPO içinde yalnızca X++ kodları bulunmuyor; tablo alanları, nesne özellikleri, form kontrolleri ve rapor bölümleri de yer alıyor. Böylece Claude Code, metotları incelerken bu kodların hangi nesneye ait olduğunu ve nasıl bir yapı içinde çalıştığını da görebilecek.
Dışa aktarımı nasıl yapacağımızı geliştirmelerin kapsamına göre belirleyebiliriz. Belirli bir modülü taşımak istiyorsak ilgili nesneleri bir proje altında toplayıp XPO olarak almak, daha kolay takip edebileceğimiz bir başlangıç sağlar. Daha geniş bir çalışma için katman bazında dışa aktarım da yapabiliriz. Ancak kapsam büyüdükçe nesneleri modüllere ve bağımlılıklarına göre gruplandırarak ilerlemek, analiz ve kontrol işini kolaylaştıracaktır.
Burada dikkat etmemiz gereken noktalardan biri, proje içindeki nesnelerin başka hangi nesnelere bağlı olduğu. Bir formu dışarı aldığımızda kullandığı özel tablo, EDT, enum veya sınıfın da elimizde olması gerekiyor. Proje ağacında gördüğümüz nesnelerle XPO içeriğini karşılaştırmak ve proje dışındaki bağımlılıkları belirlemek, dönüşüm sırasında eksik kaynaklarla karşılaşmamızı önleyecek.
Etiket dosyalarını (.ald) kullanılan dillerle birlikte kaynaklara eklemeliyiz. Örneğin XPO’daki @KBR5 kimliği, kullanıcıya gösterilen metni tek başına içermez; ilgili dilin etiket kaynağı da gerekir. Etiketlerin kaynakla birlikte hazırlanması, alan başlıklarının ve mesajların eksik taşınmasını önler.
Eski geliştirmelerde metinlerin doğrudan koda ya da nesne özelliklerine yazıldığı durumlarla da karşılaşabiliyoruz. Form başlıkları, alan açıklamaları veya kullanıcı mesajları bu şekilde tanımlanmış olabilir. Bu metinleri analiz sırasında belirleyip hedef modelde etiketlere nasıl taşıyacağımızı planlayacağız. Türkçe ve İngilizce gibi farklı dil karşılıklarının hazırlanmasını da aynı kapsamda ele alacağız.
Dosyaları topladıktan sonra hangi ortamdan, hangi proje veya katmandan ve ne zaman alındıklarını kaydetmekte fayda var. Kaynak sistemde geliştirmeler devam ediyorsa bir süre sonra aynı nesnelerin yeni sürümlerini almamız gerekebilir. Hangi kaynak dosyalarla çalıştığımızı bilmezsek, hedefte oluşan farkın yeni bir geliştirmeden mi yoksa dönüşüm sırasında yapılan bir değişiklikten mi kaynaklandığını anlamak zorlaşır.
Bu nedenle orijinal XPO ve etiket dosyalarını koruyacak, üretilen nesneleri ayrı bir klasörde tutacağız. Kaynak dosyaları, kullandığımız kural setini, hedef sürümü ve dönüşüm planını birlikte takip edeceğiz. Böylece gerektiğinde aynı kaynağa geri dönüp dönüşümü yeniden çalıştırabilecek ve sonuçları karşılaştırabileceğiz.
Kodları taşırken hangi değişiklikleri yapacağız
Kod taşıma sırasında önceliğimiz, mevcut uygulamanın işleyişini korumak olacak. Alanları, metotları ve iş kurallarını kaynak sistemle karşılaştırabileceğimiz şekilde taşıyacağız. Dynamics 365’in gerektirdiği uyarlamaları yaparken, mevcut geliştirmeyi iyileştirmek amacıyla yapılan değişiklikleri ayrıca değerlendireceğiz.
Buradaki birebir taşıma yaklaşımını, bütün nesnelerin aynı teknik yapıyla kopyalanması olarak düşünmemek gerekiyor. Örneğin bir MorphX raporunu SSRS’e dönüştürürken kullandığımız yapı değişecek. Korumaya çalıştığımız şey, raporun hangi veriyi aldığı, hangi hesaplamaları yaptığı ve kullanıcıya hangi bilgiyi sunduğu olacak.
Dönüşüm sırasında yapacağımız değişiklikleri üç grupta ele alacağız:
Tablo 2. Dönüşüm sırasında izin verilen değişiklikler
| Değişiklik türü | Nasıl uygulayacağız |
| İsimlendirme değişiklikleri | Nesne adlarını hedef model için belirlediğimiz isimlendirme kurallarına uyarlayacağız. Örneğin ZBDCarTable, DmrCarTable olacak. Bu değişikliği nesnenin kullanıldığı kodlara ve metadata referanslarına da uygulayacağız. |
| Hedef platformun gerektirdiği değişiklikler | Kaynakta kullanılan ancak hedef ortamda aynı şekilde çalışmayan yapıları uyarlayacağız. MorphX raporlarının SSRS’e taşınması, eski istemciye bağlı WinApi çağrılarının değerlendirilmesi ve güvenlik yapısının yeniden oluşturulması bu kapsama giriyor. |
| Proje kapsamında kararlaştırılan değişiklikler | Form pattern seçimi, Türkçe ve İngilizce etiketlerin hazırlanması, privilege ve duty yapısı gibi tercihleri önceden belirleyip dönüşüm planına ekleyeceğiz. |
Bu ayrım, kaynak kodda bir sorunla karşılaştığımızda özellikle önem kazanıyor. Eski uygulamada eksik bir kontrol, hatalı bir hesaplama veya performansı etkileyen bir sorgu bulunabilir. Yapay zekâ bunları analiz sırasında tespit edip düzeltme önerebilir. Ancak her öneriyi taşıma sırasında uygularsak, ortaya çıkan farkların nedenini takip etmek zorlaşır. Hedef platforma uyum için yapılan değişikliklerle mevcut işleyişi değiştiren geliştirmeler birbirine karışır.
Bu nedenle hedef ortamda çalışmayı engellemeyen iyileştirmeleri doğrudan uygulamayacağız. Bunları sorun listesinde Improvement olarak kaydedecek, etkilerini ve önerilen çözümü açıklayacağız. İlgili iş birimi veya müşteriyle değerlendirildikten sonra ayrıca ele alacağız. Böylece önce mevcut davranışın taşındığını kontrol edebilecek, sonrasında yapılacak iyileştirmeleri kendi kapsamlarında test edebileceğiz.
Dönüşüm kurallarını docs/rules altında, nesneye özgü kararları ise karar günlüğünde tutacağız. Klasör yapısını ve bu belgelerin içeriğini ilerleyen bölümlerde oluşturacağız.
Çalışma sıramız da buna göre ilerleyecek: önce kaynakların envanterini çıkaracak, ardından nesne bazında dönüşüm planını hazırlayacağız. Plan incelenip onaylandıktan sonra hedef nesneleri üretecek ve derleme kontrollerini çalıştıracağız. Karşılaştığımız hataları giderirken, sorunun yalnızca ilgili nesneden mi yoksa dönüşüm kuralından mı kaynaklandığına bakacağız. Kuralda bir eksik varsa onu da güncelleyeceğiz.
Aynı kaynak ve kural sürümleriyle çalışsak da yapay zekânın her seferinde birebir aynı dosyaları üreteceğini varsaymayacağız. Çıktıları sürüm kontrolü ve doğrulama adımlarıyla karşılaştıracağız.
Çalışmada kullanacağımız araç kiralama modülü
Süreci, AX 2009’da geliştirilmiş küçük bir araç kiralama modülü üzerinden anlatacağım. Modül; tablolar, formlar, sınıflar ve raporlar gibi farklı nesne türlerini bir arada içerdiği için dönüşüm sırasında karşılaşabileceğimiz durumları incelemek açısından uygun bir örnek oluşturuyor.
Kaynak projede toplam 43 nesne bulunuyor: 5 tablo, 2 view, 5 EDT, 4 enum, 1 sınıf, 7 form, 3 MorphX raporu, 1 query, 5 job, 1 menü ve 9 menü öğesi. Bunların tamamı özel geliştirme; değiştirilmiş standart nesne bulunmuyor. Bu sayı, dışa aktarımdaki iş nesnelerini ifade ediyor; kapsam kontrolünde kullanılan PRN proje düğümü ayrı tutuluyor.
Modüldeki metinler doğrudan kodun içine ve nesne özelliklerine Türkçe olarak yazılmış. Taşıma sırasında bu metinleri de belirleyip hedef modelin etiket yapısına alacağız.
Şekil 1. Araç kiralama modülünün AX 2009 proje ağacı.
Kaynakta bulunan her nesneyi hedefe taşımamız gerekmiyor. Önce nesnenin ne işe yaradığını, hâlâ gerekli olup olmadığını ve hedef ortamda nasıl karşılanacağını değerlendireceğiz. Bu çalışma sonunda modüldeki nesneler için aşağıdaki sonuçlar oluştu:
Tablo 3. Kaynak nesnelerin dönüşüm sonuçları
| Sonuç | Kaynak nesne sayısı | Açıklama |
| Dönüştürüldü | 36 | 67 hedef metadata öğesi üretildi; ayrıca en-us ve tr-TR karşılıkları bulunan 68 etiket kimliği hazırlandı. |
| Kapsam dışında bırakıldı | 5 | Test, eğitim ve tek seferlik veri düzeltme amacıyla hazırlanmış job’lar taşınmadı. |
| Karar bekliyor | 2 | Dosya tarama sınıfı ve ilgili menü öğesi, hedefte kullanılacak yönteme karar verilene kadar üretim kapsamı dışında tutuldu. |
Tablo 3’teki kaynak nesne sayıları 36 + 5 + 2 = 43 olarak envanterle örtüşüyor. Hedefteki 67 öğe ise dönüştürülen 36 kaynak nesneden üretilen çıktıları ifade ediyor; 68 etiket ayrı sayılıyor. Örneğin bir MorphX raporunun taşınması birden fazla SSRS bileşeni gerektiriyor. Etiket ve nesne sayıları, daha sonra göreceğimiz referans kontrolü sayılarıyla karıştırılmamalı.
Job’ları incelerken de neden kullanıldıklarına bakmak gerekiyor. Bu projedeki job’lardan biri dizi işlemlerini denemek için hazırlanmıştı ve çalıştırıldığında hata veriyordu. Bir diğeri ise herhangi bir filtre uygulamadan şirketteki bütün araçları “Servis” durumuna getiriyordu. Bu tür kodları yalnızca kaynak projede bulundukları için hedefe taşımak doğru olmayacaktır. Taşınmayan nesneleri ve gerekçelerini de dönüşüm planında kayıt altına alacağız.
Dönüştürülen nesnelerden oluşan paket, UDE ortamında xppc ile yapılan tam derleme kontrolünü sıfır hatayla tamamladı. Geliştirme ortamına deploy edildikten sonra formlar da açıldı. İlerleyen bölümlerde bu sonuca nasıl ulaştığımızı, karşılaştığımız hataları ve uygulama üzerindeki kontrolleri inceleyeceğiz.
Proje yapısını ve dönüşüm kurallarını oluşturmak
Kaynakları hazırladıktan sonra, çalışacağımız klasör yapısını kuracağız. Kaynak dosyaları, analiz belgelerini ve üretilen nesneleri ayrı yerlerde tutmak süreci takip etmeyi kolaylaştırıyor. Özellikle bir nesneyi yeniden üretmemiz gerektiğinde, orijinal dosyanın korunduğundan ve hangi kurallarla çalıştığımızdan emin olmamız gerekiyor.
Bu çalışma için aşağıdaki klasör düzenini kullanacağız:
source/AX2009/xpo/ Orijinal XPO dosyaları
source/AX2009/labels/ Orijinal .ald etiket dosyaları
docs/rules/ Dönüşüm kuralları
docs/decisions.md Alınan kararlar ve gerekçeleri
analysis/<Proje>/ Envanter, dönüşüm planı ve sorun listesi
target/D365/Metadata/ Üretilen D365 paket ve model dosyaları
CLAUDE.md Claude Code için proje talimatları
source altında tuttuğumuz dosyaları dönüşüm sırasında değiştirmeyeceğiz. Analiz ve üretim bu dosyalar üzerinden yapılacak, hedef nesneler ise target altında oluşturulacak. Böylece kaynakla hedefi karşılaştırabilecek ve gerektiğinde dönüşümü aynı kaynaklardan yeniden başlatabileceğiz.
Şekil 2. Kaynak dosyaları, analiz belgelerini, kuralları ve hedef nesneleri ayıran klasör yapısı.
Claude Code için proje talimatları
CLAUDE.md dosyasında Claude Code’un bu projede nasıl çalışmasını istediğimizi tanımlayacağız. Klasörlerin ne amaçla kullanıldığını, dönüşümün hangi sırayla ilerleyeceğini ve hangi işlemler için plan onayı gerektiğini burada açıklayacağız.
Örneğin kaynak dosyaların değiştirilmemesi, önce envanter hazırlanması, mevcut kurallarla açıklanamayan durumların kayıt altına alınması ve plan onaylanmadan hedef nesne üretilmemesi bu dosyada yer alacak. Bu talimatları proje içinde tutmak, sonraki çalışmalarda aynı kararları tekrar anlatma ihtiyacını azaltacak.
Kaynak dosyaları koruma yaklaşımını araç izinleriyle de destekleyebiliriz. Claude Code’un güncel izin yapısında dosya değiştiren yerleşik araçlar için Edit yol kuralı kullanılıyor. Proje köküne sabitlenen aşağıdaki örneği .claude/settings.json dosyasına ekleyebiliriz:
{
“permissions”: {
“deny”: ["Edit(/source/**)"]
}
}
Edit kuralı dosya düzenleyen yerleşik araçları kapsar; ayrıca Write(path) kuralı eklemek gerekmiyor. Bu ayar tüm alt süreçler için dosya sistemi düzeyinde salt okunurluk sağlamaz. Kaynakların korunmasını sürüm kontrolü ve gerektiğinde dosya sistemi izinleriyle de desteklemeliyiz. İzin davranışını kullandığımız Claude Code sürümünde kontrol edeceğiz.
Dönüşüm kurallarını nasıl tanımlayacağız
Kuralları tek bir uzun dosyada toplamak yerine konularına göre ayıracağız. İsimlendirme, tablo ve veri tipleri, formlar, sınıflar, raporlar, güvenlik ve extension yapıları için ayrı kural dosyaları kullanacağız. Böylece bir form üzerinde çalışırken ilgili form kurallarını, bir raporu taşırken rapor dönüşüm kararlarını daha kolay inceleyebileceğiz.
Her kuralın bir kimliği olacak. Ayrıca hangi kaynak yapıya uygulandığını, hedefte nasıl bir sonuç üretmesi gerektiğini ve bu kararın neden alındığını açıklayacağız. Aşağıdaki örnekler, bu çalışmada kullandığımız kurallardan bazıları:
Tablo 4. Dönüşüm kuralı örnekleri
| Kural kimliği | Kaynak yapı | Hedefte uygulanacak işlem | Dayanak |
| NAM-001 | Adı ZBD veya DT ile başlayan nesne | Önek Dmr olarak değiştirilir, adın geri kalanı korunur. | İsimlendirme kararı |
| DAT-021 | EDT üzerinde tanımlanmış ilişki | Kaynak EDT ilişkisi incelenir; ilgili tabloda uygun alan eşlemesi ve tablo ilişkisi oluşturulur. | Proje kararı; nesne bazında doğrulanır |
| DAT-026 | AllowDuplicates değeri belirtilmemiş indeks | Kaynaktaki davranışı korumak için hedefte <AllowDuplicates>Yes</AllowDuplicates> açıkça yazılır. | Dönüşüm gereksinimi |
Bu kurallar, proje için aldığımız kararları ve hedef ortamda doğruladığımız dönüşüm biçimlerini içeriyor. Başka bir projede kullanırken kaynak yapıya ve hedef sürüme uygunluklarını yeniden değerlendirmemiz gerekiyor.
Dönüşüm planındaki her nesneyi ilgili kural kimlikleriyle eşleştireceğiz. Böylece bir nesnenin neden o şekilde üretildiğini takip edebileceğiz. Mevcut kuralların karşılamadığı bir durumla karşılaşırsak, Claude Code’dan tahminde bulunarak devam etmesini istemeyeceğiz. Önce durumu ve önerilen çözümü sorun listesine ekleyecek, değerlendirdikten sonra yeni bir kural veya nesneye özel bir karar oluşturacağız.
Claude Code’u çalışmaya hazırlamak
Proje talimatlarını hazırladıktan sonra Claude Code’a ilk analiz görevini verebiliriz. Bu aşamada kaynakları, ilgili kural dosyalarını, hedef konumu ve doğrulama komutlarını birlikte erişilebilir tutacağız.
Çalışan referans model, üretim sırasında kullanılacak hedef yapıyı gösterecek. Envanter ve planlama aşamasında ise önceliğimiz, kaynak nesnelerle eksik bağımlılıkları belirlemek olacak.
İlk görevimiz kod üretmekten önce kaynakları incelemek olacak. Bunun için aşağıdaki gibi bir başlangıç talimatı kullanabiliriz:
Kaynak XPO ve etiket dosyalarını incele. Nesnelerin listesini, aralarındaki bağımlılıkları, eksik referansları ve varsa standart nesne değişikliklerini belirle. Her nesne için uygulanacak dönüşüm kurallarını ve karar verilmesi gereken konuları içeren bir yükseltme planı hazırla. Kaynak dosyaları değiştirme ve plan onaylanmadan hedef metadata üretme.
Bu talimatla önce neyi taşıyacağımızı ve hangi konuların açıklığa kavuşması gerektiğini göreceğiz. Örneğin kaynakta bulunmayan bir sınıfa referans varsa veya eski bir işlevin hedefte nasıl karşılanacağı belli değilse, kod üretimine geçmeden bunları değerlendirebileceğiz.
Analiz ve üretim boyunca aynı derleme, etiket ve metadata kontrol betiklerini kullanacağız. Bu kontrollerin nasıl çalıştığını “Üretilen nesneleri derlemek ve doğrulamak” bölümünde ele alacağız.
XPO içindeki nesnelerin envanterini çıkarmak
Dönüşüm planını hazırlayabilmek için önce elimizdeki XPO’nun içeriğini netleştirmemiz gerekiyor. Hangi nesneler var, bunlar birbirlerini nerelerde kullanıyor ve kaynak pakette eksik bir parça bulunuyor mu? Bu soruların cevaplarını envanter belgesinde toplayacağız.
Yalnızca nesne adlarını listelemek yeterli olmayacak. Nesnenin özel geliştirme mi yoksa değiştirilmiş bir standart nesne mi olduğunu, kullandığı veri tiplerini, ilişkilerini ve etiketlerini de belirleyeceğiz. Böylece taşıma kapsamını ve bağımlılıkları birlikte görebileceğiz.
XPO içindeki nesne bölümlerini ayırırken ***Element: <kod> satırlarından yararlanabiliriz. Araç kiralama projesinin dışa aktarımında aşağıdaki nesne kodları bulunuyor:
Tablo 5. XPO nesne türü kodları
| Kod | Nesne türü | Açıklama |
| DBT | Tablo | Alanlar, indeksler, ilişkiler ve tablo metotları incelenir. |
| VIE | View | Veri kaynakları ve kullanılan alanlar belirlenir. |
| UTS | Extended data type | Temel veri tipi, özellikler ve varsa ilişkiler incelenir. |
| DBE | Base enum | Enum elemanları ve değerleri belirlenir. |
| CLS | Sınıf | Metotlar ve kullanılan nesneler incelenir. |
| JOB | Job | Kullanım amacı ve taşınmasına ihtiyaç olup olmadığı değerlendirilir. |
| FRM | Form | Veri kaynakları, kontroller ve form metotları incelenir. |
| RG | MorphX raporu | Kaynak dosyadaki tür kodunun sonunda boşluk bulunuyor; ayrıştırma sırasında dikkate alınır. |
| QUE | Query | Veri kaynakları, alanlar, ilişkiler ve filtreler incelenir. |
| MNU | Menü | Menü yapısı ve bağlı menü öğeleri belirlenir. |
| FTM | Menü öğesi | Type değerine göre display, output veya action olarak değerlendirilir: sırasıyla 1, 2, 3. |
| PRN | Proje düğümü | Hedef nesneye dönüştürülmez; içerdiği nesne listesi kapsam kontrolünde kullanılır. |
Bu inceleme sırasında özellikle üç konu üzerinde duracağız.
Kaynak dosyaların eksiksiz olduğunu kontrol etmek
Önce proje düğümündeki nesnelerle XPO içinde gerçekten bulunan nesneleri karşılaştıracağız. Ardından menülerin, formların ve kodların referans verdiği özel nesnelerin kaynaklarda bulunup bulunmadığına bakacağız.
Araç kiralama modülünde menünün, XPO içinde bulunmayan iki menü öğesine referans verdiğini gördük. Eksik nesneleri tahmin ederek üretmek yerine ilgili dışa aktarımı istemeli veya referansların artık kullanılmadığını doğrulamalıyız. Bu dış referanslar, 43 kaynak nesnenin dönüşüm sonuçlarından ayrı bir eksik kaynak kaydı olarak izlenmeli; “karar bekliyor” satırındaki sınıf ve menü öğesiyle karıştırılmamalı.
Standart nesnelerin hedefteki karşılığını incelemek
Kaynak kodda kullanılan standart nesne ve alanların hedef sürümde aynı şekilde bulunduğunu varsayamayız. Nesnenin adı korunmuş olsa bile alanları, metotları veya ilişkileri değişmiş olabilir.
Örneğin bu modülde CustTable üzerindeki Name, Phone ve TeleFax alanlarına yapılan erişimleri ayrıca değerlendirmek gerekti. Hedefte aynı isimli bir alan aramakla yetinmeden, ilgili bilginin yeni veri modelinde nasıl tutulduğunu ve hangi metot veya ilişki üzerinden alınacağını inceleyeceğiz. Müşteri adı ile iletişim bilgilerinin karşılıklarını da ayrı ayrı doğrulayacağız.
Bunun için hedef ortamın PackagesLocalDirectory yapısındaki standart metadata dosyalarından yararlanabiliriz. İlgili nesnenin XML dosyasını bulduktan sonra alanlarını, metotlarını ve bağlı olduğu yapıları inceleyerek dönüşüm kararını oluşturacağız.
Paket bağımlılıklarını belirlemek
Kullandığımız standart nesnenin hangi pakette bulunduğunu da envantere ekleyeceğiz. Hedef modelin derlenebilmesi için gerekli paket referanslarının tanımlanmış olması gerekiyor. Kaynak kod açısından doğru görünen bir kullanım, modelin ModuleReferences listesinde ilgili paket bulunmadığında derleme hatasına neden olabilir.
Bu bağımlılıkları analiz sırasında belirlemek, üretimden sonra karşılaşacağımız hataları azaltacak. Ayrıca hedef modelin hangi standart paketlere bağlı olduğunu baştan görmemizi sağlayacak.
Bu aşamanın sonunda analysis/<Proje>/inventory.md altında nesne türlerini, kaynaklarını, bağımlılıklarını, etiketlerini ve eksiklerini içeren bir envanterimiz olacak. Bir sonraki adımda her nesne için taşıma kararını bu belge üzerinden verecek ve uygulanacak kuralları dönüşüm planına işleyeceğiz.
Yükseltme planını hazırlamak
Envanteri çıkardıktan sonra, her nesneyi hedef ortamda nasıl ele alacağımızı belirleyeceğiz. Hangi nesneler mevcut işleviyle taşınacak, hangileri yeniden tasarlanacak, hangilerine artık ihtiyaç yok? Kod üretimine başlamadan önce bu kararları netleştirmek, hem kapsamı kontrol etmemizi hem de üretilen sonucu kaynakla karşılaştırmamızı kolaylaştıracak.
Plan içinde her nesnenin hedefteki karşılığını, uygulanacak kural kimliklerini ve varsa bekleyen kararları göstereceğiz. Claude Code da üretim sırasında bu planı esas alacak. Açıklığa kavuşmamış bir konu varsa önce onu değerlendirecek, planı inceleyip onayladıktan sonra hedef nesneleri oluşturmaya başlayacağız.
Nesneler için kullanacağımız temel kararlar şöyle:
Tablo 6. Nesne bazında taşıma kararları
| Karar | Nasıl ele alacağız | Örnek |
| Migrate | Mevcut işlevi koruyarak taşıyacağız. İsimlendirme değişikliklerini, hedef platformun gerektirdiği uyarlamaları ve onaylanan proje kararlarını uygulayacağız. | Tablolar, formlar ve raporlar |
| Redesign | Kaynaktaki yöntem hedef ortamda aynı şekilde kullanılamıyorsa, işlevi nasıl karşılayacağımızı yeniden tasarlayacağız. | Kullanıcının bilgisayarında yerel dosya diyaloğu açan sınıf |
| Drop | Nesneyi taşımayacak, neden kapsam dışında bıraktığımızı kaydedeceğiz. | Test ve eğitim amacıyla hazırlanmış job’lar |
| Covered by standard | İhtiyaç hedef sürümün standart işlevleriyle karşılanıyorsa özel geliştirmeyi taşımayacağız. | Araç kiralama modülünde bu kapsamda bir nesne bulunmuyor. |
Burada teknik yapının değişmesiyle işlevin yeniden tasarlanmasını ayırmak gerekiyor. Örneğin MorphX raporunun SSRS bileşenlerine dönüştürülmesi, mevcut rapor davranışını koruyorsak taşıma kapsamında değerlendirilebilir. Kullanıcının işlemi yapma biçimi veya iş akışı değişecekse ayrıca tasarım kararı vermemiz gerekir.
Kaynak ve hedef nesne adlarını eşleştirmek
Planın önemli parçalarından biri isim haritası olacak. Kaynaktaki nesne adlarıyla hedefte kullanacağımız adları tek bir yerde tutacağız. Örneğin ZBDReservationTable tablosunun hedefteki karşılığı DmrReservationTable olacak.
Bu eşleştirmeyi yalnızca nesnenin kendi adını değiştirirken kullanmayacağız. Kod içindeki kullanımlar, form veri kaynakları, tablo ilişkileri, query’ler ve menü öğeleri de aynı haritaya göre güncellenecek. Böylece bir nesnenin adı değişirken ona bağlı referansların eski isimle kalmasını önleyebileceğiz.
Zorunlu kod değişikliklerini belirlemek
Hedef sürüme uyum için gereken değişiklikleri de plan içinde kaynak ve hedef karşılıklarıyla göstereceğiz. Böylece üretimden önce hangi kodun neden değişeceğini inceleyebileceğiz.
Rezervasyon tablosundaki müşteri adını getiren metot buna basit bir örnek:
AX 2009
// ZBDReservationTable
display CustName dispCustName()
{
;
return CustTable::find(this.CustAccount).Name;
}
Dynamics 365
// DmrReservationTable
display CustName dispCustName()
{
;
return CustTable::find(this.CustAccount).name();
}
Kaynak kodda müşteri adı Name alanından okunuyor. Hedefte ise bu bilgiyi name() metodu üzerinden alıyoruz. Bu nedenle alan erişimini metot çağrısına dönüştürüyoruz.
Metodun geri kalanını aynı bırakıyoruz. Kaynaktaki gereksiz noktalı virgülü bile bu aşamada temizlemiyoruz. Bunun nedeni, taşıma sırasında yaptığımız değişiklikleri gerekli uyarlamalarla sınırlı tutmak. Kod temizliği veya yeniden düzenleme ihtiyacı varsa bunları ayrıca değerlendirebiliriz.
Araç kiralama modülü için hazırlanan planda bu türden 51 zorunlu değişiklik bulunuyor. Bu değişiklikleri üretimden önce listelemek, hedefte oluşan kodu incelerken bize bir kontrol listesi de sağlıyor.
Bekleyen konuları ve üretim sırasını planlamak
Planı tamamlamadan önce eksik kaynakları ve karşılanması gereken koşulları da belirleyeceğiz. Eksik etiket dosyaları, eklenmesi gereken paket referansları veya müşteriden beklenen iş kararları burada yer alacak. Bu konuların hangi nesneleri etkilediğini ve üretimi engelleyip engellemediğini açıkça göstereceğiz.
Ardından nesneleri hangi sırayla oluşturacağımızı belirleyeceğiz. Enum ve EDT gibi temel tanımlarla başlayıp bunları kullanan tablolara ve ilişkilere geçebiliriz. View, query, sınıf, form ve rapor bileşenlerini de bağımlılıklarına göre sıraya alacağız. Etiketleri, menüleri ve güvenlik öğelerini ilgili nesnelerle birlikte tamamlayacağız.
Bu sıra her projede aynı olmayacak. Envanterde belirlediğimiz bağımlılıklar, hangi nesnenin önce hazırlanması gerektiğini gösterecek. Üretimi küçük gruplar halinde yürütüp aralarda derleme kontrolü yapmak, bir hata oluştuğunda hangi değişiklikten kaynaklandığını bulmamızı kolaylaştıracak.
Bu aşamanın sonunda elimizde yalnızca taşınacak nesnelerin listesi bulunmayacak. Her nesne için alınan kararı, hedef adını, uygulanacak kuralları, zorunlu değişiklikleri ve bekleyen konuları içeren bir çalışma planımız olacak. Planı inceleyip onayladıktan sonra hedef nesnelerin üretimine geçeceğiz.
Dynamics 365 nesnelerini oluşturmak
Dönüşüm planını hazırladıktan sonra hedef nesneleri oluşturmaya başlayabiliriz. Bu aşamada Claude Code, kaynak XPO içeriğini, isim haritasını ve belirlediğimiz kuralları kullanarak Dynamics 365 metadata dosyalarını üretecek.
Üretilen dosyaları aşağıdaki klasör yapısında tutacağız:
target/D365/Metadata/<Paket>/<Model>/Ax<Tip>/
Tablolar AxTable, sınıflar AxClass, formlar ise AxForm gibi ilgili nesne türüne ait klasörlerde yer alacak. Bu düzen, üretilen nesneleri hedef model içinde incelememizi ve geliştirme ortamına almamızı kolaylaştıracak.
XML dosyalarını oluştururken referans modeldeki kök elemanları, namespace tanımlarını, özellik sırasını ve boş koleksiyonların gösterimini esas alacağız. Modelde bulunmayan türlerde aynı hedef sürümden sade bir standart örnek seçeceğiz. Bu çalışmada raporlar ve view’lar için standart örneklerden yararlandık.
Şekil 3 (solda). Üretilen DmrContoso modelindeki enum ve tablo nesneleri.
Şekil 4 (sağda). D365 projesine alınan sınıflar, formlar, etiketler, menüler ve raporlar.
Metadata yapısını ve kaynak davranışını korumak
Dosyaların biçimini de üretim kurallarının bir parçası olarak tanımlayacağız. Bu çalışmada nesne XML’lerini BOM’suz UTF-8 ve CRLF satır sonlarıyla, etiket dosyalarını ise BOM’lu UTF-8 olarak oluşturuyoruz. Bu ayrıntıları baştan belirlemek, üretilen dosyaların aynı düzeni izlemesini ve sürüm kontrolündeki farkların daha kolay okunmasını sağlayacak.
Ancak doğru XML üretmek kadar, özelliklerin hedefte hangi davranışı oluşturduğunu kontrol etmek de gerekiyor. Kaynakta açıkça yazılmamış bir özellik, hedefte farklı bir varsayılan değerle yorumlanabilir. Böyle bir durumda dosya yapısal olarak doğru olsa bile uygulamanın davranışı değişebilir.
İndekslerdeki AllowDuplicates özelliği buna bir örnek. Bu çalışmada, kaynakta tekrar eden değerlere izin veren indekslerin hedefte de aynı davranışı koruması için ilgili değeri açıkça yazıyoruz:
<AxTableIndex>
<Name>ModelYearIdx</Name>
<AllowDuplicates>Yes</AllowDuplicates>
<Fields>
<AxTableIndexField>
<DataField>ModelYear</DataField>
</AxTableIndexField>
<AxTableIndexField>
<DataField>ColorId</DataField>
</AxTableIndexField>
</Fields>
</AxTableIndex>
Burada korumak istediğimiz davranış, aynı model yılı ve renk değerlerine sahip birden fazla kaydın bulunabilmesi. Dönüşüm sırasında indeksin yanlışlıkla benzersiz hale gelmesi, veri girişi veya senkronizasyon sırasında sorun oluşturabilir. Bu nedenle yalnızca kaynakta yazılı özellikleri kopyalamakla yetinmeyecek, varsayılan değerlerin etkisini de değerlendireceğiz.
Formları uygun pattern ile oluşturmak
Formları taşırken önce kaynak formun nasıl kullanıldığını inceleyeceğiz. Tek bir liste mi gösteriyor, ana veri ve detay bilgilerini mi içeriyor, yoksa başlık ve satırlardan oluşan bir işlem yapısı mı var? Seçeceğimiz form pattern’i bu yapıya göre belirleyeceğiz.
Araç kiralama modülünde veri kaynakları, başlık–satır ilişkisi, alan sayısı ve tablo grubu gibi on özelliği dikkate aldık. Beş adımlı değerlendirme sonunda uygun pattern’i seçip gerekçesini Form Karar Kartı’na kaydettik. Bu değerlendirme akışı projenin kural setine ait; aşağıdaki tablo sonuçları özetliyor.
Bu değerlendirme sonucunda aşağıdaki dağılım oluştu:
Tablo 7. Yedi form için seçilen pattern dağılımı
| AX 2009 form yapısı | Hedef ortamda kullanılan pattern | Form sayısı |
| Tek grid ve az sayıda alan | Simple List 1.1 | 3 |
| Ana veri ve detay grupları | Details Master 1.4 | 1 |
| Başlık ve satırlar | Details Transaction 1.4 | 3 |
Tablo 7’deki 3 + 1 + 3 dağılımı, envanterdeki 7 formun tamamını kapsıyor. Pattern sürümleri bu çalışmada kullanılan 10.0.2527.116 geliştirme ortamına ait; farklı bir hedefte gereksinimleri yeniden kontrol etmeliyiz.
Pattern’i uygularken kaynak formun işlevini ve alanların anlamlı sırasını koruyacağız. Butonların Action Pane’e taşınması, sabit boyutların ve eski istemciye özgü renk ayarlarının kaldırılması gibi düzenlemeler yapacağız. Grupları ve başlıkları da mümkün olduğunca koruyacağız; ancak hedef pattern’in gerektirdiği durumlarda kontrol hiyerarşisini yeniden düzenlememiz gerekebilir. Bu değişiklikleri form kararına ekleyerek kaynakla hedef arasındaki farkı takip edeceğiz.
MorphX raporlarını SSRS yapısına dönüştürmek
Raporlarda daha kapsamlı bir dönüşüm yapmamız gerekiyor. AX 2009’daki MorphX raporlarını hedefte aynı nesne yapısıyla kullanamayacağımız için veri hazırlama kodunu ve rapor tasarımını SSRS yapısında yeniden oluşturacağız.
Bu çalışmada her rapor için yedi bileşenden oluşan bir yapı kullanıyoruz:
- Rapor verisini tutacak TempDB geçici tablo
- Veri seçimi ve filtreler için query
- Rapor parametreleri için contract sınıfı
- Veriyi hazırlayacak RDP sınıfı
- Raporun çalıştırılmasını yönetecek controller sınıfı
- Alanların ve yerleşimin tanımlandığı rapor tasarımı
- Raporu uygulamadan açacak output menü öğesi
Bu yapı, burada kullandığımız dönüşüm yaklaşımı. Kaynak raporun veri hazırlama ve çıktı üretme mantığını bu bileşenler arasında paylaştıracağız.
Tablo 8. MorphX ile SSRS bileşenlerinin eşleştirilmesi
| MorphX tarafındaki yapı | Bu çalışmada kullanılan SSRS karşılığı |
| Rapor içindeki query | Ayrı bir AxQuery; kullanıcıya açılacak filtreler rapor diyaloğunda düzenlenir. |
| fetch() ve send() akışı | RDP sınıfındaki processReport() içinde veri hazırlama ve geçici tabloya kayıt ekleme işlemleri |
| Otomatik yerleşimli bölümler (AUTOBODIES) | Sütun sırasını koruyacak şekilde Auto design |
| Alan üzerindeki SumAll | İlgili kapsamda genel toplam |
| Display metotlar ve kodda oluşturulan metinler | Hesaplanarak geçici tablo alanlarına yazılan değerler |
| Kodla belirlenen renkler | Rapor tasarımındaki renk ifadeleri |
Örneğin kaynak raporda send() ile çıktı üretilen noktaları inceleyerek hedefte geçici tabloya hangi kaydın yazılacağını belirleyeceğiz. Display metotlardan gelen değerleri de RDP içinde hesaplayıp raporun kullanacağı alanlara aktaracağız. Böylece kaynak rapordaki hesaplamaları ve çıktı satırlarını hedef bileşenlerle eşleştirebileceğiz.
Otomatik yerleşimli rapor bölümleri için Auto design kullanmayı tercih ettik. Böylece sütun sırasını koruyarak yerleşimi yeniden oluşturduk ve elle RDL hazırlama ihtiyacını azalttık. Bu tercih, tüm raporlar için zorunlu bir yöntem değil; kaynak yerleşime ve beklenen çıktı biçimine göre ayrıca değerlendirilmeli.
Yine de aynı veriyi üretmek, aynı görsel çıktıyı elde ettiğimiz anlamına gelmiyor. Kaynaktaki milimetre cinsinden konumlar ve şekiller bu yaklaşımla birebir taşınmıyor. Başlıkları, sütun genişliklerini, toplamları ve sayfalamayı rapor çıktısı üzerinde ayrıca karşılaştıracağız. Tespit ettiğimiz farkları da test listesine ekleyerek değerlendireceğiz.
Şekil 5. MorphX raporları için üretilen contract, controller ve RDP sınıfları.
Bu aşamanın sonunda hedef modelin nesneleri oluşmuş olacak. Sonraki adımda üretilen metadata ve X++ kodlarını derleyerek kontrol edecek, ardından geliştirme ortamında formları ve raporları çalıştırarak doğrulamaya devam edeceğiz.
Üretilen nesneleri derlemek ve doğrulamak
Üretimi küçük gruplar halinde yürütüp her grubun ardından derleme kontrolü yapacağız. Bu kontrol, kod ve metadata hatalarını erken bulmamızı sağlar; nesnelerin işlevsel olarak birlikte çalıştığını ise uygulama testleriyle doğrulayacağız.
Bu kontroller için UDE ortamındaki xppc derleyicisini kullanacağız. Hazırladığımız betik, paketi doğrudan target klasöründen alıp aktif UDE yapılandırmasındaki Microsoft paketlerine karşı derleyecek. Her küçük değişiklikte Visual Studio üzerinden build başlatmadan, kod ve metadata kaynaklı hataları daha erken görebileceğiz.
Komut satırından derleme kontrolü
Derleme betiği, aktif ortamın FrameworkDirectory yolunu aşağıdaki registry konumundan okuyor:
HKCU\Software\Microsoft\Dynamics\AX7\Development\Configurations
Ardından bu yolu kullanarak xppc çağrısını oluşturuyor. Aşağıdaki gösterim okunabilirlik için satırlara ayrıldı; betik bu parametreleri tek bir derleyici çağrısına aktarıyor:
xppc -metadata=<target> -compilermetadata=<target> -modelmodule=DmrContoso
-referenceFolder=<FrameworkDirectory> -refPath=<FrameworkDirectory>\bin
-output=%TEMP%\xppc-ude-scratch\DmrContoso
Buradaki <target> ve <FrameworkDirectory> değerleri betik tarafından gerçek klasör yollarıyla dolduruluyor. Komut, hedefte ürettiğimiz paketi ilgili ortamın standart paketlerini referans alarak derliyor.
Geliştirme sırasında küçük değişiklikleri kontrol etmek için artımlı derlemeden yararlanabiliriz. Ancak bir üretim grubunu tamamladığımızda tam derleme yapacağız. Etiket kontrolünü de aynı aşamada çalıştıracağız.
Bu çalışma için hazırladığımız betiği aşağıdaki komutla çağırıyoruz:
powershell.exe -NoProfile -ExecutionPolicy Bypass `
-File “.claude/skills/d365-xpp-compile-ude/scripts/Invoke-XppUdeBuild.ps1″ `
-Full -CheckLabels
Invoke-XppUdeBuild.ps1 ve buradaki parametreler, kullandığımız proje betiğine ait. -Full tam derlemeyi, -CheckLabels ise ayrıca hazırladığımız etiket denetimini çalıştırıyor.
Etiket referanslarını kontrol etmek
Kodun derlenmesi, kullanıcıya gösterilecek bütün metinlerin doğru hazırlandığını tek başına göstermiyor. Bu nedenle etiket referanslarını ayrıca kontrol edeceğiz.
-CheckLabels seçeneği, kod ve metadata içinde kullanılan @DmrContoso: önekli etiket kimliklerinin hem en-us hem de tr-TR dosyalarında bulunup bulunmadığını denetliyor. Böylece nesne üzerinde bir etiket referansı bulunmasına rağmen ilgili dil dosyasında metnin eksik kaldığı durumları yakalayabiliyoruz. Bu kontrol etiketin varlığını doğruluyor; çevirinin doğruluğunu ve metnin kullanıcı açısından uygunluğunu ayrıca incelememiz gerekiyor.
Araç kiralama modülündeki derleme ve kontrol işlemleri sonunda aşağıdaki sonucu aldık:
RESULT: SUCCEEDED – 0 errors, 1 warnings in package elements, …
Pakette derleme hatası kalmadı. Tek uyarıyı ise kaynak koddan gelen, davranışı değiştirmeden taşıdığımız bir sorunla ilişkili olduğu için kayıt altında bıraktık. Düzeltmesini ayrı bir karar olarak değerlendireceğiz. Burada önemli olan, uyarıları gözden kaçırmak yerine neden kaldıklarını ve nasıl ele alınacaklarını açıklayabilmek.
XML dosyalarının doğru okunduğunu doğrulamak
Derlemenin yanında metadata dosyaları için de bir kontrol yapacağız. XML’in geçerli olması, içindeki her özelliğin hedef araçlar tarafından beklediğimiz şekilde okunduğu anlamına gelmeyebilir.
Bu çalışmada kullandığımız metadata serileştirme yapısında özelliklerin sırası önemli. Yanlış sıraya yazılmış bir özellik, okuma sırasında hata oluşmadan atlanabiliyor. Böyle bir durumda dosyanın içinde gördüğümüz bir değer, nesne geliştirme araçlarında açıldığında etkili olmayabilir.
Bunu kontrol etmek için üretilen XML’i Microsoft’un metadata kütüphanesindeki ilgili tipe okuyup yeniden XML olarak yazıyoruz. Ardından ilk dosyayla yeniden oluşturulan dosyayı karşılaştırıyoruz. Bu işleme round-trip kontrolü diyebiliriz.
Bir tablo için kullandığımız yaklaşımın basitleştirilmiş hali şöyle:
Add-Type -AssemblyName System.Runtime.Serialization
$bin = “$env:LOCALAPPDATA\Microsoft\Dynamics365\10.0.2527.116″
$bin = Join-Path $bin “PackagesLocalDirectory\bin”
$asm = [Reflection.Assembly]::LoadFrom(
“$bin\Microsoft.Dynamics.AX.Metadata.dll”
)
$type = $asm.GetType(
“Microsoft.Dynamics.AX.Metadata.MetaModel.AxTable”
)
$ser = New-Object Runtime.Serialization.DataContractSerializer($type)
$obj = $ser.ReadObject(
[Xml.XmlReader]::Create(“DmrCarTable.xml”)
)
$w = [Xml.XmlWriter]::Create(“DmrCarTable.roundtrip.xml”)
$ser.WriteObject($w, $obj)
$w.Close()
Örnekteki kütüphane yolu bu çalışmanın geliştirme paketine ait; kendi ortamımızdaki yolu ve yüklü kütüphaneleri kullanmalıyız. Bu kod temel okuma–yazma işlemini gösteriyor. Gerçek betikte okuyucu ve yazıcıların kapatılması, hata yönetimi ve karşılaştırma adımı da bulunmalı.
Tablolarda uyguladığımız bu kontrol, formlar gibi farklı kontrol tiplerini bir arada içeren nesnelerde ek hazırlık gerektiriyor. Bu tür nesneler için serializer’a ilgili tipleri içeren bir known types listesi sağlamak ve gerektiğinde bağımlı DLL’lerin yüklenmesini bir AssemblyResolve işleyicisiyle yönetmek gerekiyor.
Karşılaştırmada gördüğümüz her farkı da hata olarak değerlendirmeyeceğiz. Serializer bazı varsayılan değerleri yeniden yazmayabilir. Örneğin CreateRecIdIndex = Yes değerinin çıktı dosyasında bulunmaması durumunda, ilgili tipin varsayılanını ve okunan nesnedeki değeri kontrol edeceğiz. Asıl aradığımız, verdiğimiz bir özelliğin kaybolması veya beklenenden farklı yorumlanması.
Bu kontrol sırasında bir form grubundaki Columns özelliğinin Caption özelliğinden önce gelmesi gerektiğini tespit ettik. Düzeltmeyi yalnızca ilgili forma uygulamakla kalmayıp sonraki üretimlerde kullanılacak kurala da ekledik.
Nesneler arasındaki tutarlılığı kontrol etmek
Derleme ve XML kontrollerinden sonra, üretilen modelin planla uyumunu inceleyeceğiz. Bunun için kullandığımız tutarlılık betiği; tablo, EDT, enum, sınıf, menü öğesi ve etiket referanslarının çözümlenip çözümlenmediğine bakıyor. Nesne adlarının isim haritasına uyduğunu ve dönüştürülmesi gereken yerlerde eski öneklerin kalmadığını da kontrol ediyor.
Bu betik, kontrol çalıştırmasında 172 öğe referansı ve 113 etiket referansını doğruladı. Bunlar benzersiz nesne veya etiket sayıları değil, kontrol edilen kullanımlardır; aynı tanıma birden fazla yerde başvurulabilir. Bu nedenle baştaki 67 hedef öğe ve 68 etiket sayısıyla doğrudan karşılaştırılmamalıdır.
Kontrol sürecinde, üretimin önceki aşamasında eksik kalan iki view ve bir query de bulundu ve tamamlandı. Buradaki tespit ara kontrole, sıfır hata sonucu ise düzeltmelerden sonraki derlemeye ait. Böylece derleme başarısıyla kapsamın eksiksizliğini ayrı ayrı değerlendirebiliyoruz.
Geliştirme ortamında çalıştırmak
Komut satırından yaptığımız kontroller, üretim sırasında hızlı geri bildirim almamızı sağlıyor. Ancak bunlar geliştirme ortamındaki build, veritabanı senkronizasyonu ve deploy işlemlerinin yerine geçmiyor.
Bu kontroller tamamlandıktan sonra paketi UDE geliştirme ortamına alıp gerekli build ve veritabanı senkronizasyonunu yapacağız. Raporlar için de deploy işlemini tamamlayacağız. Ardından uygulamayı açarak menüleri, formları ve raporları kontrol edeceğiz.
Şekil 6. Deploy sonrasında web istemcisinde görünen Car tracking menüsü.
Menünün uygulamada görünmesiyle birlikte, bağlı menü öğelerinin doğru form ve raporlara yönlendirdiğini inceleyebiliriz. Formlarda ise veri kaynaklarının, alanların ve başlık–satır ilişkilerinin hedef istemcide nasıl çalıştığına bakacağız.
Şekil 7. Dynamics 365 üzerinde açılan araç ve rezervasyon formunun başlık ve satır yapısı.
Veri girilmiş araç formunda ne görüyoruz
Formun açılmasının ardından Cars ekranına test kayıtları girerek alanların hedef istemcide nasıl göründüğünü inceledim. Şekil 8’de C0001, C0002 ve C0003 kimlikli üç kayıt var. Model yılı, model, marka, araç sınıfı, plaka, renk ve araç durumu sütunları aynı grid üzerinde görülüyor. Bunlar hedefte girilmiş test kayıtları; AX 2009 veritabanından veri aktarımı yapıldığını göstermiyor.
Şekil 8. Dynamics 365 Cars formuna girilmiş üç test kaydı.
Kayıt listelemeyi doğruladıktan sonra yeni kayıt açma, düzenleme, silme, zorunlu alanlar, ilişkiler, enum değerleri ve filtre davranışı test edilmeli. Örneğin aynı araç kimliğinin tekrar girilmesi, ilişkili rezervasyonu bulunan aracın silinmesi veya geçersiz bir sınıf değerinin seçilmesi ayrı test senaryolarıdır. Ekran görüntüsü bu senaryoların tamamının geçtiği anlamına gelmez; dönüşümün fonksiyonel doğrulamasını bu senaryolarla genişletmemiz gerekir.
SSRS raporunu çalıştırmak ve çıktıyı kontrol etmek
Rapor bileşenlerini oluşturup derledikten sonra, raporu uygulama içinden çalıştırarak kontrol edeceğiz. Böylece veri hazırlama kodundan rapor tasarımına kadar oluşturduğumuz yapının birlikte nasıl çalıştığını görebileceğiz.
Araç kiralama modülündeki raporu deploy edip Dynamics 365 üzerinden açtığımızda, forma girdiğimiz araçların çıktıda listelendiğini görüyoruz. Aşağıdaki görüntüde raporun ilk sayfası yer alıyor.
Şekil 9. Dynamics 365 içinden çalıştırılan SSRS raporunun ilk sayfası ve araç kayıtları.
Çıktıda C0001, C0002 ve C0003 araç kimlikleriyle birlikte marka bilgileri bulunuyor. Bu kayıtları araç formundaki verilerle karşılaştırarak ilk kontrolümüzü yapabiliriz. Formda gördüğümüz kayıtların rapora gelmesi, veri hazırlama ve çıktı üretme akışının çalıştığını gösteriyor. Ardından raporun içeriğini ve yerleşimini daha ayrıntılı incelememiz gerekiyor.
Kaynak nesnelerle hedef nesneleri karşılaştırmak
Formları ve raporları uygulama üzerinde kontrol ederken, üretilen nesnelerin kaynakla ilişkisini de takip etmemiz gerekiyor. XPO ile XML farklı yapılara sahip olduğu için dosyaları doğrudan satır satır karşılaştırmak bize yeterli bilgi vermeyecek. Önce isim haritasını kullanarak her kaynak nesneyi hedefteki karşılığıyla eşleştireceğiz.
Ardından nesnenin içeriğine bakacağız. Tablolarda alanları, veri tiplerini, metotları, indeksleri ve ilişkileri; diğer nesnelerde de kendi yapılarına uygun özellikleri karşılaştıracağız. Örneğin bir alanın hedef tabloda bulunması tek başına yeterli değil. Uzunluğu, zorunluluk durumu, kullandığı EDT ve ilişkileri de planladığımız şekilde oluşmalı. İndekslerde ise alan sırasının ve tekrar eden değerlere izin verilip verilmediğinin korunduğunu kontrol edeceğiz.
Formlarda kaynak kontrol yapısıyla hedef pattern’i birlikte değerlendireceğiz. Bir butonun Action Pane’e taşınması, hedef tasarıma uyum için yaptığımız bir düzenleme olabilir. Ancak butonun çağırdığı metodun veya menü öğesinin eksik kalması, giderilmesi gereken bir dönüşüm sorunudur. Alanların ve grupların yerleşimi değişse bile kullanıcının yaptığı işlemin ve bu işlemin sonucunun korunmasını bekleyeceğiz.
Raporlarda da kaynak kodun hedefte nasıl karşılandığını izleyebilmeliyiz. Kaynaktaki fetch() ve send() akışının RDP sınıfında hangi işlemlere dönüştüğünü, hesaplanan değerlerin hangi geçici tablo alanlarına yazıldığını ve tasarımda nerede kullanıldığını kontrol edeceğiz. Böylece çıktıda bir eksik gördüğümüzde veri seçiminden hesaplamaya ve tasarıma kadar ilgili adımı bulabileceğiz.
Karşılaştırma sonunda gördüğümüz farkları dönüşüm planıyla birlikte değerlendireceğiz. Önceden kararlaştırılmış bir uyarlama varsa gerekçesi planda bulunacak. Açıklayamadığımız bir fark varsa sorun listesine ekleyip inceleyeceğiz.
Düzeltme yaptığımızda da değişikliği yalnızca üretilen XML dosyasında bırakmayacağız. Sorun genel bir dönüşüm kuralından kaynaklanıyorsa ilgili kuralı güncelleyeceğiz. Yalnızca o nesneye özgü bir durumsa kararını ve uygulanacak işlemi kaydedeceğiz. Böylece aynı kaynağı yeniden işlediğimizde yaptığımız düzeltmenin kaybolmasını önleyebileceğiz.
Son olarak yeni üretilen dosyaları sürüm kontrolündeki önceki halleriyle karşılaştıracağız. Bu inceleme, beklediğimiz düzeltmelerin uygulandığını ve diğer nesnelerde istemediğimiz değişiklikler oluşmadığını görmemizi sağlayacak.
Dönüşüm sırasında karşılaştığımız hatalar
Araç kiralama modülünü taşırken xppc kontrollerinde toplam 19 derleme hatasıyla karşılaştık. Bu hatalar beş grupta toplandı. Bazıları eksik paket referanslarından, bazıları ise form pattern’lerinin ve query yapılarının hedef ortamda beklediği özelliklerden kaynaklanıyordu.
Hata tablosunda, bu çalışmada tespit ettiğimiz nedenleri ve uyguladığımız çözümleri topladık. Kural seti bu bulgulara göre güncellendi.
Tablo 9. Derleme hatalarının nedenleri ve çözümleri
| Hata kodu | Bu çalışmada karşılaştığımız neden | Uyguladığımız çözüm |
| EdtDoesNotExist, UnderlyingFieldTypeNotFound | Kullanılan standart Price EDT’si ApplicationCommon paketindeydi, ancak hedef modelde bu pakete referans bulunmuyordu. | ApplicationCommon paketini modelin ModuleReferences listesine ekledik. |
| TableDisplayEditReturnTypeUnknown | Formdaki CustTable veri kaynağı üzerinden kontrol edilen display metotlarından mcrIsMerged, Retail paketindeki bir tipe bağımlıydı. | Retail referansını ekledik. Veri kaynağındaki alan listesini daraltmak bu hatayı çözmedi. |
| PatternPropertyRequiredValue | Kullanılan Details Transaction pattern’inin beklediği bazı özellikler eksikti. | Satır grid’inde VisibleRows = 5 ve VisibleRowsMode = Fixed, satır detay sekmesinde ise Style = Tabs değerlerini tanımladık. |
| PatternControlNotAllowed | Kullandığımız Fields and Field Groups alt pattern’inde, kaynak formdan gelen iç içe grup yapısı kabul edilmiyordu. | Fazladan dış grubu kaldırıp iç grupları doğrudan ilgili FastTab altına taşıdık. |
| FieldListEmpty | Üretilen rapor query’lerinde alan listesi boştu ve dinamik alan seçimi açık değildi. | Kaynaktaki tüm alanları seçme davranışını karşılamak için ilgili veri kaynaklarında <DynamicFields>Yes</DynamicFields> tanımladık. |
Bu hata kodlarını tek bir çözüme bağlı genel kurallar olarak düşünmemek gerekiyor. Örneğin EdtDoesNotExist, başka bir nesnede eksik üretilmiş veya yanlış adlandırılmış bir EDT nedeniyle de oluşabilir. Burada yaptığımız, hata mesajından başlayıp ilgili nesneyi ve bağımlılıklarını inceleyerek nedeni belirlemek oldu.
Eksik paket referanslarını tamamlamak
Paket referansları, özel geliştirmeyi taşırken kolayca gözden kaçabilecek konulardan biri. Kaynak kodda kullandığımız standart bir nesnenin hedef ortamda bulunması yeterli olmuyor. Hedef modelin, o nesnenin bulunduğu pakete de referans vermesi gerekiyor.
CustTable üzerinden karşılaştığımız hata bu açıdan dikkat çekiciydi. Formdaki alan listesini daraltmamıza rağmen derleyici display metotlarıyla ilgili bağımlılığı kontrol etmeye devam etti. Sorunu, ilgili dönüş tipinin bulunduğu Retail paketini referanslara ekleyerek çözebildik.
Bu incelemeyi Claude Code ile de yürütebiliriz. Hata mesajındaki nesneyi hedef metadata içinde arayıp hangi pakette bulunduğunu belirlemesini, mevcut referansları kontrol etmesini ve gerekli değişikliği hazırlamasını isteyebiliriz. Ardından derlemeyi yeniden çalıştırarak değişikliğin sonucu kontrol edilir.
Paket referansları modelin Descriptor/<Model>.xml dosyasındaki ModuleReferences bölümünde tanımlanıyor. Bu çalışmadaki referans listesi şöyle:
<ModuleReferences xmlns:d2p1=”http://schemas.microsoft.com/2003/10/Serialization/Arrays”>
<d2p1:string>ApplicationCommon</d2p1:string>
<d2p1:string>ApplicationFoundation</d2p1:string>
<d2p1:string>ApplicationPlatform</d2p1:string>
<d2p1:string>ApplicationSuite</d2p1:string>
<d2p1:string>Retail</d2p1:string>
</ModuleReferences>
Bu listeyi başka bir modele doğrudan kopyalamak yerine, o modelin gerçekten ihtiyaç duyduğu paketleri belirlemeliyiz. Eklenen her referans modelin bağımlılık kapsamını genişletiyor ve sonraki güncellemelerde dikkate alınması gereken bir ilişki oluşturuyor.
Bu nedenle gerekli referansı önce paketin çalışma kopyasına ekleyip derledik. Hatanın giderildiğini gördükten sonra değişikliği esas çıktıya aldık ve neden eklendiğini karar günlüğüne yazdık.
Kontrol araçlarını da doğrulamak
Dönüşüm sırasında karşılaştığımız her sorun üretilen koddan kaynaklanmadı. Etiket kontrolü bir noktada, dosyalarda bulunan bazı etiketleri eksik olarak raporladı. Nedeni, betikte kullandığımız büyük/küçük harfe duyarsız -match karşılaştırmasının Türkçe yerel ayarda “I” harfini farklı eşleştirmesiydi. Karşılaştırmayı harfe duyarlı -cmatch ile değiştirerek sorunu giderdik. Bu örnek, doğrulama araçlarını da test etmemiz gerektiğini gösteriyor: Bir kontrol hata verdiğinde, üretilen nesne kadar kontrolün kendisini de incelemeliyiz. Düzeltmeyi ortak betiğe uygulayarak sonraki etiket kontrollerinde de kullanılmasını sağladık.
Gerçek bir projede nasıl ilerleyebiliriz
Araç kiralama modülü, farklı nesne türlerini birlikte incelememizi sağladı. Ancak tamamı özel geliştirmelerden oluşan, kapsamı sınırlı bir modüldü. Gerçek bir projede standart nesne değişiklikleri, entegrasyonlar, toplu işler, belge işlemleri ve daha karmaşık bağımlılıklarla karşılaşabiliriz.
Bu nedenle benzer bir çalışmaya başlarken önce bağımlılıklarını anlayabildiğimiz bir modül seçmek faydalı olacaktır. Bu modül üzerinden hem dönüşüm kurallarını hem de kontrol araçlarını sınayabiliriz. Hangi işlemlerin tekrar kullanılabildiğini, nerelerde uzman kararı gerektiğini ve hangi nesnelerin daha fazla uğraştırdığını görebiliriz.
İlk olarak üzerinde çalışacağımız kaynak sürümü sabitleyeceğiz. Ardından nesne envanterini çıkarıp mevcut geliştirmelerin hedefteki standart işlevlerle karşılanıp karşılanmadığını değerlendireceğiz. İsim haritasını ve dönüşüm planını hazırladıktan sonra üretim, derleme, senkronizasyon ve uygulama kontrollerini yürüteceğiz.
Bu ilk çalışmanın sonunda çalışan modelle birlikte harcanan süreleri ve elle müdahale ettiğimiz noktaları da incelemeliyiz. Bir sonraki modüle geçmeden önce eksik kuralları tamamlamak ve tekrar eden işlemleri betiklere almak, sonraki çalışmaları daha düzenli yürütmemizi sağlayacaktır.
Standart nesne değişikliklerini değerlendirmek
Standart nesneler üzerinde geliştirme yapılmışsa ek bir analiz gerekiyor. Önce değiştirilen nesneyi, aynı AX sürümünün değiştirilmemiş standart haliyle karşılaştırmalıyız. Böylece hangi alanların, metotların veya iş kurallarının sonradan eklendiğini belirleyebiliriz.
Ardından bu değişikliğin hedef sürümde nasıl karşılanacağını değerlendireceğiz. İhtiyaç artık standartta karşılanıyor olabilir veya hedefte farklı bir veri modeli kullanılıyor olabilir. Geliştirmeye hâlâ ihtiyaç varsa uygun extension noktalarını inceleyip Chain of Command, event handler veya diğer genişletme seçeneklerinden hangisinin kullanılacağına karar vereceğiz.
Araç kiralama modülünde değiştirilmiş standart nesne bulunmadığı için bu çalışmayla o kısmı doğrulamış olmadık. Bunun için farklı örnekler üzerinde kaynak fark analizi, hedef tasarım ve fonksiyonel testler yapmamız gerekiyor.
Canlıya geçiş hazırlığında da kod taşımanın dışında işlerimiz olacak. Rol ve yetki kontrolleri, entegrasyon testleri, veri aktarımı, performans değerlendirmesi ve kullanıcı kabulü ayrıca yürütülmeli. Ürettiğimiz model bu çalışmaların bir parçasını oluşturacak.
AX 2012 için de kullanabilir miyiz
Kaynakları analiz etme, dönüşüm kurallarını tanımlama, kararları kaydetme ve üretilen sonucu doğrulama yaklaşımını AX 2012’den Dynamics 365’e geçiş çalışmalarında da kullanabiliriz. Ancak AX 2009 için hazırladığımız kuralları değiştirmeden uygulamak yerine, kaynak sürümün yapısına göre yeniden değerlendirmemiz gerekiyor.
AX 2012’den geçişte mevcut yükseltme araçlarını ve bunların proje kapsamını ne ölçüde karşıladığını da başlangıçta değerlendirmeliyiz. Yapay zekâ desteğini kaynak kod farklarını incelemek, kalan uyarlamaları planlamak, extension seçeneklerini değerlendirmek ve dönüşüm sonrası kontrolleri yürütmek için kullanabiliriz.
Sonuç
Bu yazıda örnek bir araç kiralama projesi üzerinden, AX 2009’daki X++ kodlarını yapay zekâ desteğiyle Dynamics 365’e nasıl daha hızlı taşıyabileceğimizi anlattım. XPO analizinden hedef nesnelerin oluşturulmasına, derleme kontrollerinden veri girilen formlara ve SSRS çıktısına kadar ilerledik. Çalışma sonunda oluşan 157 kural ve 28 kayıtlı karar, sonraki projelerde de yararlanabileceğimiz bir birikim sağladı.
Elbette bir sürüm yükseltme projesi yalnızca kod taşımakla tamamlanmıyor. Yeni sürümle gelen standart fonksiyonları, yıllar içinde değişen iş ihtiyaçlarını ve artık gerekli olmayan geliştirmeleri de değerlendirmek gerekiyor. Veri aktarımı, entegrasyonlar, güvenlik, testler ve kullanıcıların yeni sisteme hazırlanması da bu sürecin önemli parçaları.
Bununla birlikte, kod analizi ve dönüşümünde bu tür bir kullanımın ciddi bir hız kazanımı sağlayabileceğini düşünüyorum. Özellikle tekrar eden işleri kurallara bağlamak ve her aşamada doğrulamak, teknik ekibin işlevsel kararlar ve daha karmaşık uyarlamalar için zaman ayırmasını sağlayabilir.
Bu örnekte özel nesnelerden oluşan sınırlı bir modülle çalıştık. Sonraki adım, aynı yaklaşımı daha karmaşık bağımlılıklar ve standart nesne değişiklikleri üzerinde uygulamak olacak. Her yeni çalışmada kuralları geliştirerek, kod yükseltme sürecinde yeniden kullanabileceğimiz daha kapsamlı bir altyapı oluşturmayı hedefliyorum.
Bu çalışmada kullandığım örnek dosyaları, dönüşüm kurallarını ve betikleri buradan indirebilirsiniz. Kendi projenizde kullanmadan önce kaynak ve hedef sürümünüze göre inceleyip uyarlamanızı öneririm.
Selamlar.
Fatih Demirci















No comments yet.