muhtemelen
Doğası gereği genel bir bakış olan bu makalede, entegre geliştirme araçları oluşturmaya yönelik bir platform olarak Eclipse mimarisinin bazı temellerine bakmaya çalışacağız ve teknolojinin temelini oluşturan Eclipse bileşenleri hakkında ilk fikir vermeye çalışacağız. “yeni Yapılandırıcı” 1C: Enterprise platformu.
Eclipse Mimarisine Giriş
Öncelikle şu örneği kullanarak Eclipse mimarisinin bazı genel yönlerine bakalım
Her şeyden önce, Eclipse'in, dilden bağımsız işlevselliğin belirli programlama dillerini desteklemek için tasarlanmış işlevsellikten ayrılması ve kullanıcı arayüzünden bağımsız "çekirdek" bileşenlerin ilişkili bileşenlerden ayrılmasıyla oldukça net bir mimari katmanlama ile karakterize edildiğine dikkat edilmelidir. Destekleyici kullanıcı arayüzü ile.
Böylece Eclipse Platformu ortak, dilden bağımsız bir altyapı tanımlar ve Java geliştirme araçları Eclipse'e tam özellikli bir Java IDE ekler. Hem Eclipse Platformu hem de JDT, her biri kullanıcı arayüzünden bağımsız bir "çekirdeğe" veya bir kullanıcı arayüzü katmanına ait olan çeşitli bileşenlerden oluşur (Şekil 1).
Pirinç. 1. Eclipse Platformu ve JDT
Eclipse Platformunun ana bileşenlerini sıralayalım:
- Süre — Eklenti altyapısını tanımlar. Eclipse modüler bir mimariye sahiptir. Esas itibarıyla Eclipse, "uzatma noktaları" ve "uzantılar"dan oluşan bir koleksiyondur.
- çalışma alanı — Bir veya daha fazla projeyi yönetir. Bir proje, doğrudan dosya sistemine eşlenen klasörlerden ve dosyalardan oluşur.
- Standart Widget Araç Takımı (SWT) - İşletim sistemiyle entegre temel kullanıcı arayüzü öğeleri sağlar.
- JYüz — SWT'nin üzerine inşa edilmiş bir dizi kullanıcı arayüzü çerçevesi sağlar.
- Tezgâh — Eclipse UI paradigmasını tanımlar: editörler, görüşler, bakış açıları.
Eclipse Platformunun ayrıca entegre geliştirme araçları oluşturmak için Hata Ayıklama, Karşılaştırma, Arama ve Ekip dahil olmak üzere birçok başka yararlı bileşen sağladığını da söylemek gerekir. Kaynak kodun “akıllı editörlerini” oluşturmanın temeli olan JFace Text'den özellikle bahsetmek gerekir. Ne yazık ki, bu makalenin kapsamında bu bileşenlerin yanı sıra kullanıcı arayüzü katmanı bileşenlerinin üstünkörü bir incelemesi bile mümkün değildir, bu nedenle bu bölümün geri kalanında kendimizi ana "temel" bileşenlere genel bir bakışla sınırlayacağız. Eclipse Platformu ve JDT.
Çekirdek Çalışma Zamanı
Eclipse eklenti altyapısı dayanmaktadır
Temel Çalışma Alanı
Eclipse Platformu üzerine inşa edilen neredeyse tüm entegre geliştirme ortamları, Eclipse çalışma alanıyla çalışır. Genellikle IDE'de geliştirilen uygulamanın kaynak kodunun bulunduğu çalışma alanıdır. Çalışma alanı doğrudan dosya sistemiyle eşlenir ve klasörler ve dosyalar içeren projelerden oluşur. Bu projelere, klasörlere ve dosyalara denir Kaynaklar çalışma alanı. Eclipse'deki çalışma alanı uygulaması, dosya sistemiyle ilgili olarak bir önbellek görevi görür ve bu, kaynak ağacının geçişini önemli ölçüde hızlandırmayı mümkün kılar. Ayrıca, çalışma alanı aşağıdakiler de dahil olmak üzere bir dizi ek hizmet sağlar:
Temel Kaynaklar bileşeni (org.eclipse.core.resources eklentisi), çalışma alanının ve kaynaklarının desteklenmesinden sorumludur. Özellikle bu bileşen, formdaki çalışma alanına programlı erişim sağlar kaynak modelleri. Bu modelle etkili bir şekilde çalışmak için müşterilerin bir kaynağa bağlantı sunmanın basit bir yoluna ihtiyacı vardır. Bu durumda, modeldeki kaynağın durumunu doğrudan saklayan nesnenin istemci erişiminden gizlenmesi arzu edilir. Aksi takdirde, örneğin bir dosyanın silinmesi durumunda, müşteri artık modelde olmayan bir nesneyi tutmaya devam edebilir ve bunun sonucunda sorunlar ortaya çıkabilir. Eclipse bu sorunu adı verilen bir şeyi kullanarak çözer. sap kaynak. Handle bir anahtar görevi görür (yalnızca çalışma alanındaki kaynağın yolunu bilir) ve kaynağın durumu hakkındaki bilgileri doğrudan depolayan dahili model nesnesine erişimi tamamen kontrol eder. Bu tasarım desenin bir varyasyonudur
Pirinç. Şekil 2, kaynak modeline uygulanan Tutamaç/Gövde deyimini göstermektedir. IResource arabirimi bir kaynağın tanıtıcısını temsil eder ve bu arabirimi uygulayan Resource sınıfından ve API olmayan gövdeyi temsil eden ResourceInfo sınıfından farklı olarak bir API'dir. Sapın yalnızca çalışma alanı köküne göre kaynağın yolunu bildiğini ve kaynak bilgisine bir bağlantı içermediğini vurguluyoruz. Kaynak bilgisi nesneleri sözde "öğe ağacı" oluşturur. Bu veri yapısı tamamen hafızada hayata geçirilmiştir. Bir tanıtıcıya karşılık gelen kaynak bilgisi örneğini bulmak için öğe ağacı, bu tanıtıcıda saklanan yola göre geçilir.
Pirinç. 2. IResource ve ResourceInfo
Daha sonra göreceğimiz gibi, kaynak modelinin temel tasarımı (buna tanıtıcı tabanlı diyebiliriz) Eclipse'de diğer modellerde de kullanılıyor. Şimdilik bu tasarımın ayırt edici özelliklerinden bazılarını sıralayalım:
- Handle bir değer nesnesidir. Değer nesneleri, eşitliği kimliğe dayanmayan değişmez nesnelerdir. Bu tür nesneler karma kaplarda anahtar olarak güvenle kullanılabilir. Birden fazla tanıtıcı örneği aynı kaynağa başvurabilir. Bunları karşılaştırmak için equals(Object) yöntemini kullanmanız gerekir.
- Tanıtıcı bir kaynağın davranışını tanımlar, ancak kaynağın durumu hakkında bilgi içermez (depoladığı tek veri "anahtar"dır, yani kaynağa giden yoldur).
- Tanıtıcı, var olmayan bir kaynağa atıfta bulunabilir (henüz oluşturulmamış bir kaynak veya zaten silinmiş bir kaynak). Bir kaynağın varlığı IResource.exists() yöntemi kullanılarak kontrol edilebilir.
- Bazı işlemler yalnızca tanıtıcının kendisinde depolanan bilgilere dayanarak gerçekleştirilebilir (yalnızca tanıtıcı işlemler olarak adlandırılır). Örnekler IResource.getParent(), getFullPath() vb.'dir. Böyle bir işlemin başarılı olması için kaynağın mevcut olmasına gerek yoktur. Başarılı olmak için bir kaynağın var olmasını gerektiren işlemler, kaynak yoksa bir CoreException oluşturur.
Eclipse, çalışma alanı kaynak değişikliklerini bildirmek için etkili bir mekanizma sağlar (Şekil 3). Kaynaklar, Eclipse IDE'nin kendisinde gerçekleştirilen eylemlerin bir sonucu olarak veya dosya sistemiyle senkronizasyonun bir sonucu olarak değişebilir. Her iki durumda da bildirimlere abone olan müşterilere, değişikliklere ilişkin ayrıntılı bilgiler “kaynak deltaları” şeklinde sunulur. Delta, bir çalışma alanı kaynak (alt) ağacının iki durumu arasındaki değişiklikleri tanımlar ve kendisi de bir ağaçtır; her düğümü bir kaynakta yapılan değişikliği tanımlar ve alt kaynaklarda yapılan değişiklikleri açıklayan sonraki düzeydeki deltaların bir listesini içerir.
Pirinç. 3. IResourceChangeEvent ve IResourceDelta
Kaynak deltalarına dayalı bildirim mekanizması aşağıdaki özelliklere sahiptir:
- Delta yinelemeli kompozisyon ilkesi kullanılarak oluşturulduğundan, tek bir değişiklik ve birçok değişiklik aynı yapı kullanılarak tanımlanır. Abone istemcileri, bir delta ağacı aracılığıyla özyinelemeli iniş kullanarak kaynak değişikliği bildirimlerini işleyebilir.
- Delta, kaynağın hareketi ve/veya onunla ilişkili "işaretçiler"deki değişiklikler de dahil olmak üzere, kaynakta yapılan değişiklikler hakkında tam bilgi içerir (örneğin, derleme hataları işaretçiler olarak gösterilir).
- Kaynak referansları tanıtıcı aracılığıyla yapıldığından, delta doğal olarak uzak bir kaynağa referans verebilir.
Yakında göreceğimiz gibi, kaynak modeli değişikliği bildirim mekanizmasının tasarımının ana bileşenleri diğer tanıtıcı tabanlı modeller için de geçerlidir.
JDT Çekirdeği
Eclipse çalışma alanı kaynak modeli, dilden bağımsız temel bir modeldir. JDT Core bileşeni (eklenti org.Eclipse.jdt.core), çalışma alanı yapısında Java perspektifinden gezinmek ve analiz etmek için "Java modeli" olarak adlandırılan bir API sağlar (Java modeli). Bu API, klasörler ve dosyalar cinsinden tanımlanan temel kaynak modeli API'sinin aksine, Java öğeleri açısından tanımlanır. Java eleman ağacının ana arayüzleri Şekil 4'de gösterilmektedir. XNUMX.
Pirinç. 4. Java Model Öğeleri
Java modeli, kaynak modeliyle aynı tanıtıcı/gövde deyimini kullanır (Şekil 5). IJavaElement tanıtıcıdır ve JavaElementInfo gövde rolünü oynar. IJavaElement arayüzü, tüm Java öğeleri için ortak bir protokol tanımlar. Yöntemlerinden bazıları yalnızca tanıtıcıdır: getElementName(), getParent(), vb. JavaElementInfo nesnesi, karşılık gelen öğenin durumunu, yani yapısını ve niteliklerini saklar.
Pirinç. 5. IJavaElement ve JavaElementInfo
Java modelinin, kaynak modeline kıyasla temel tanıtıcı/gövde tasarımının uygulanmasında bazı farklılıkları vardır. Yukarıda belirtildiği gibi kaynak modelinde, düğümleri kaynak bilgi nesneleri olan öğe ağacının tamamı bellekte bulunur. Ancak Java modeli, kaynak ağacından önemli ölçüde daha fazla sayıda öğeye sahip olabilir çünkü aynı zamanda .java ve .class dosyalarının iç yapısını da temsil eder: türler, alanlar ve yöntemler.
Bellekteki öğe ağacının tamamının tamamen hayata geçirilmesini önlemek için, Java modeli uygulaması, anahtarın IJavaElement tanıtıcısı olduğu sınırlı boyutlu bir LRU öğe bilgisi önbelleği kullanır. Öğe ağacında gezindikçe öğe bilgisi nesneleri talep üzerine oluşturulur. Bu durumda, en az kullanılan öğeler önbellekten çıkarılır ve modelin bellek tüketimi, belirtilen önbellek boyutuyla sınırlı kalır. Bu, bu tür uygulama ayrıntılarını istemci kodundan tamamen gizleyen tanıtıcı tabanlı tasarımın bir başka avantajıdır.
Java öğelerindeki değişiklikleri bildirme mekanizması genel olarak yukarıda tartışılan çalışma alanı kaynaklarındaki değişiklikleri izleme mekanizmasına benzer. Java modelindeki değişiklikleri izlemek isteyen bir istemci, IJavaElementDelta içeren bir ElementChangedEvent nesnesi olarak temsil edilen bildirimlere abone olur (Şekil 6).
Pirinç. 6. ElementChangedEvent ve IJavaElementDelta
Java modeli, yöntem gövdeleri veya ad çözümlemesi hakkında bilgi içermediğinden, Java'da yazılan kodun ayrıntılı analizi için JDT Core ek (tanımlayıcı tabanlı olmayan) bir model sağlar:
Sözdizimi ağaçları önemli miktarda bellek tüketebildiğinden JDT, etkin düzenleyici için yalnızca bir AST'yi önbelleğe alır. Java modelinin aksine, AST tipik olarak "ara", "geçici" bir model olarak görülür; istemcilerin, AST'nin oluşturulmasına yol açan işlemin bağlamı dışında referanslara sahip olmaması gereken öğeler.
Listelenen üç model (Java modeli, AST, bağlamalar), çeşitli "yardımcılara" sahip güçlü bir Java düzenleyicisi, kaynak kodunu işlemek için çeşitli eylemler (bir içe aktarma listesi düzenlemek dahil) dahil olmak üzere JDT'de "akıllı geliştirme araçları" oluşturmanın temelini oluşturur. özelleştirilmiş stile göre adlar ve biçimlendirme), arama ve yeniden düzenleme araçları. Bu durumda Java modeli, geliştirilmekte olan uygulamanın yapısının görsel temsili için temel olarak kullanıldığı için özel bir rol oynar (örneğin, Paket Gezgini, Anahat, Arama, Çağrı Hiyerarşisi ve Hiyerarşi yazın).
1C:Enterprise Development Tools'da kullanılan Eclipse bileşenleri
İncirde. Şekil 7, 1C:Kurumsal Geliştirme Araçları için teknoloji platformunun temelini oluşturan Eclipse bileşenlerini göstermektedir.
Pirinç. 7. 1C:Kurumsal Geliştirme Araçları platformu olarak Eclipse
Eclipse Platformu temel altyapıyı sağlar. Önceki bölümde bu altyapının bazı yönlerine baktık.
Gerçekten genel amaçlı herhangi bir araç gibi, EMF de çok çeşitli modelleme problemlerini çözmeye uygundur, ancak bazı model sınıfları (örneğin, yukarıda tartışılan tutamaç tabanlı modeller) daha özel modelleme araçları gerektirebilir. EMF hakkında konuşmak, özellikle bir makalenin sınırlı sınırları içinde nankör bir iştir, çünkü bu ayrı bir kitabın konusu ve oldukça kalın bir konudur. Sadece EMF'nin altında yatan yüksek kaliteli genellemeler sisteminin, üst düzey projeye dahil olan modellemeye adanmış bir dizi projenin doğmasına izin verdiğini not edelim.
1C:Enterprise Development Tools, hem EMF'nin kendisini hem de bir dizi diğer Eclipse Modelleme projesini aktif olarak kullanıyor. Özellikle Xtext, yerleşik programlama dili ve sorgulama dili gibi 1C:Enterprise dilleri için geliştirme araçlarının temellerinden biridir. Bu geliştirme araçlarının bir diğer temeli, daha ayrıntılı olarak tartışacağımız Eclipse Handly projesidir (listelenen Eclipse bileşenleri arasında hala en az bilinenidir).
Tutamaç/gövde deyimi gibi tanıtıcı tabanlı modellerin temel mimari ilkeleri, örnek olarak kaynak modeli ve Java modeli kullanılarak yukarıda tartışılmıştır. Ayrıca hem kaynak modelinin hem de Java modelinin Eclipse Java geliştirme araçları (JDT) için önemli temeller olduğu belirtildi. Ve neredeyse tüm *DT Eclipse projeleri JDT'ye benzer bir mimariye sahip olduğundan, Eclipse Platformu üzerine inşa edilen IDE'lerin hepsi olmasa da çoğunun altında tanıtıcı tabanlı modellerin yattığını söylemek büyük bir abartı olmaz. Örneğin, Eclipse C/C++ Development Tooling (CDT), Java modelinin JDT'de oynadığı rolün aynısını CDT mimarisinde oynayan tanıtıcı tabanlı bir C/C++ modeline sahiptir.
Handly'den önce Eclipse, tanıtıcı tabanlı dil modelleri oluşturmak için özel kütüphaneler sunmuyordu. Şu anda mevcut olan modeller esas olarak Java model kodunun doğrudan uyarlanmasıyla (diğer adıyla kopyala/yapıştır) oluşturulmuştur. izin verdiği durumlarda Eclipse Kamu Lisansı (EPL). (Açıkçası, bu genellikle örneğin Eclipse projelerinin kendisi için yasal bir sorun değildir, ancak kapalı kaynak ürünler için geçerli değildir.) Kendi doğası gereği gelişigüzelliğine ek olarak, bu teknik iyi bilinen sorunları da beraberinde getirir: hatalara uyum sağlarken ortaya çıkan kod çoğaltması, vesaire. Daha da kötüsü, ortaya çıkan modellerin “kendi başına şeyler” olarak kalması ve birleşme potansiyelinden yararlanamamasıdır. Ancak tanıtıcı tabanlı dil modelleri için ortak kavramların ve protokollerin izole edilmesi, EMF durumunda olduğu gibi, onlarla çalışmak için yeniden kullanılabilir bileşenlerin oluşturulmasına yol açabilir.
Eclipse'in bu sorunları anlamadığı söylenemez. 2005 yılında
Belirli bir anlamda, Handly projesi EMF ile yaklaşık olarak aynı sorunları çözmek için tasarlanmıştır, ancak tanıtıcı tabanlı modeller ve öncelikle dil modelleri (yani bazı programlama dilinin yapısının öğelerini temsil eden) için tasarlanmıştır. Handly'yi tasarlarken belirlenen ana hedefler aşağıda sıralanmıştır:
- Konu alanının ana soyutlamalarının belirlenmesi.
- Kodun yeniden kullanımı yoluyla tanıtıcı tabanlı dil modellerinin uygulama kalitesinin artırılması ve çabanın azaltılması.
- Ortaya çıkan modellere birleşik bir meta düzeyinde API sağlayarak, dil tanıtıcısı tabanlı modellerle çalışan ortak IDE bileşenleri oluşturmayı mümkün kılar.
- Esneklik ve ölçeklenebilirlik.
- Xtext ile entegrasyon (ayrı bir katmanda).
Ortak kavramları ve protokolleri vurgulamak için dil tanıtıcısı tabanlı modellerin mevcut uygulamaları analiz edildi. Handly tarafından sağlanan ana arayüzler ve temel uygulamalar Şekil 8'de gösterilmektedir. XNUMX.
Pirinç. 8. Handly elemanlarının ortak arayüzleri ve temel uygulamaları
IElement arayüzü bir öğenin tanıtıcısını temsil eder ve tüm Handly tabanlı modellerin öğelerinde ortaktır. Soyut sınıf Element genelleştirilmiş tutamaç/gövde mekanizmasını uygular (Şekil 9).
Pirinç. 9. IElement ve genel tanıtıcı/gövde uygulaması
Ek olarak Handly, model öğelerindeki değişiklikler hakkında bildirimde bulunmak için genelleştirilmiş bir mekanizma sağlar (Şekil 10). Gördüğünüz gibi, kaynak modelinde ve Java modelinde uygulanan bildirim mekanizmalarına genel olarak benzer ve öğe değişikliği bilgilerinin birleşik bir temsilini sağlamak için IElementDelta'yı kullanır.
Pirinç. 10. Handly bildirim mekanizmasının genel arayüzleri ve temel uygulamaları
Yukarıda tartışılan Handly kısmı (Şekil 9 ve 10), hemen hemen tüm kulp tabanlı modelleri temsil etmek için kullanılabilir. Oluşturmak için dilsel modellerde, proje ek işlevsellik sunar - özellikle ortak arayüzler ve kaynak metin yapısının unsurları için temel uygulamalar. kaynak elemanları (Şekil 8). ISourceFile arabirimi bir kaynak dosyayı temsil eder ve ISourceConstruct, kaynak dosya içindeki bir öğeyi temsil eder. SourceFile ve SourceConstruct soyut sınıfları, kaynak dosyalar ve bunların öğeleriyle çalışmayı desteklemek için genelleştirilmiş mekanizmalar uygular; örneğin, metin arabellekleriyle çalışma, kaynak metindeki bir öğenin koordinatlarına bağlanma, modelleri çalışan bir kopya arabelleğinin geçerli içeriğiyle uzlaştırma , vesaire. Bu mekanizmaların uygulanması genellikle oldukça zorludur ve Handly, yüksek kaliteli temel uygulamalar sağlayarak tanıtıcı tabanlı dil modelleri geliştirme çabasını önemli ölçüde azaltabilir.
Yukarıda listelenen temel mekanizmalara ek olarak Handly, metin arabellekleri ve anlık görüntüler için bir altyapı, kaynak kodu düzenleyicileriyle entegrasyon desteği (Xtext düzenleyicisiyle kullanıma hazır entegrasyon dahil) ve ayrıca bazı ortak kullanıcı arayüzü bileşenleri sağlar. Anahat çerçevesi gibi kaynak kodu editörleriyle çalışın. Yeteneklerini göstermek için proje, Java modelinin Handly'de uygulanması da dahil olmak üzere çeşitli örnekler sunmaktadır. (JDT'deki Java modelinin tam uygulamasıyla karşılaştırıldığında, bu model daha fazla netlik sağlamak amacıyla kasıtlı olarak bir miktar basitleştirilmiştir.)
Daha önce belirtildiği gibi, Handly'nin ilk tasarımı ve sonraki geliştirmesi sırasında ana odak noktası ölçeklenebilirlik ve esneklik olmuştur ve olmaya devam etmektedir.
Prensip olarak, tutamak tabanlı modeller "tasarım gereği" oldukça iyi ölçeklenir. Örneğin, tanıtıcı/gövde deyimi, bir model tarafından tüketilen bellek miktarını sınırlamanıza olanak tanır. Ancak nüanslar da var. Bu nedenle, Handly'yi ölçeklenebilirlik açısından test ederken, bildirim mekanizmasının uygulanmasında bir sorun keşfedildi - çok sayıda öğe değiştirildiğinde, deltaların oluşturulması çok fazla zaman aldı. Aynı sorunun, ilgili kodun bir zamanlar uyarlandığı JDT Java modelinde de mevcut olduğu ortaya çıktı. Handly'deki hatayı düzelttik ve JDT için de benzer bir yama hazırladık. Bu yama memnuniyetle karşılandı. Bu, Handly'nin mevcut model uygulamalarına dahil edilmesinin potansiyel olarak yararlı olabileceği örneklerden sadece bir tanesidir, çünkü bu durumda böyle bir hata tek bir yerden düzeltilebilir.
Handly'nin mevcut model uygulamalarına uygulanmasını teknik olarak mümkün kılmak için kütüphanenin önemli ölçüde esnekliğe sahip olması gerekir. Asıl sorun, API modeli genelinde geriye dönük uyumluluğu korumaktır. Bu sorun şu tarihte çözüldü:
Esnekliğin başka yönleri de vardır. Örneğin, Handly modelin yapısına neredeyse hiçbir kısıtlama getirmez ve hem genel amaçlı hem de alana özgü dilleri modellemek için kullanılabilir. Kaynak dosyanın yapısını oluştururken Handly, herhangi bir özel AST temsili biçimi önermez ve prensip olarak bir AST'nin varlığını bile gerektirmez, böylece neredeyse tüm ayrıştırma mekanizmalarıyla uyumluluk sağlanır. Son olarak Handly, Eclipse çalışma alanıyla tam entegrasyonu destekler ancak entegrasyonu sayesinde dosya sistemleriyle de doğrudan çalışabilir.
Şimdiki versiyonu
Yukarıda belirtildiği gibi, bu ürünlerden biri 1C:Enterprise Geliştirme Araçları'dır; burada Handly, yerleşik programlama dili ve sorgu dili gibi 1C:Enterprise dillerinin üst düzey yapısının elemanlarını modellemek için en başından beri kullanılır. . Başka bir ürün halk tarafından daha az biliniyor. Bu
API kararlılığı garantisiyle 1.0 sürümünün piyasaya sürülmesinden ve projenin kuluçka aşamasından çıkmasından sonra Handly'nin yeni benimseyicilere sahip olacağını umuyoruz. Bu arada proje, API'yi test etmeye ve daha da geliştirmeye devam ediyor; Haziran ayında (eş zamanlı Eclipse sürümüyle aynı tarih) ve Aralık ayında olmak üzere yılda iki "büyük" sürüm yayınlayarak, benimseyenlerin güvenebileceği öngörülebilir bir program sağlıyor. Ayrıca projenin "hata oranının" sürekli düşük seviyede kaldığını ve Handly'nin ilk sürümlerden bu yana erken benimseyenlerin ürünlerinde güvenilir bir şekilde çalıştığını da ekleyebiliriz. Eclipse Handly'yi daha fazla keşfetmek için şunları kullanabilirsiniz:
Kaynak: habr.com