diff --git a/_posts/2023-12-28-java-module-system.md b/_posts/2023-12-28-java-module-system.md index 02fe0ab..2d039cb 100644 --- a/_posts/2023-12-28-java-module-system.md +++ b/_posts/2023-12-28-java-module-system.md @@ -1,7 +1,7 @@ --- -title: "The State of the Java Module System - Mark Reinhold (Java Modül Sisteminin Durumu) (ÇEVİRİ)" +title: "Java Modül Sisteminin Durumu - Mark Reinhold (ÇEVİRİ)" comments: false -excerpt: "Arkadaşlar bu yazı Mark Reinhold'un, Java'da modül sistemi ile ilgili kaleme aldığı meşhur bir makaledir. Çevirisini bizzat kendim yaptım." +excerpt: "Arkadaşlar bu yazı Mark Reinhold'un, Java'da modül sistemi ile ilgili kaleme aldığı 'The State of the Module System' isimli meşhur bir makaledir." header: teaser: "/assets/images/svg-book6.svg" og_image: /assets/images/svg-book6.svg @@ -16,6 +16,8 @@ categories: - recommends tags: - Java modül sistemi + - principle of least surprise + - implied readability (requires transitive) #last_modified_at: 2023-01-06T15:12:19-04:00 last_modified_at: toc: true @@ -138,7 +140,7 @@ module java.base { exports java.lang; exports java.lang.annotation; exports java.lang.invoke; - exports java.lang.module; + exports java.lang.module; exports java.lang.ref; exports java.lang.reflect; exports java.math; @@ -153,7 +155,7 @@ Geriye kalan platform modülleri **“java.”** isim önekini paylaşacak ve mu ## 2 USING MODULES (modülleri kullanma) -Bireysel modüller, modül yapılarında (*module artifacts*) tanımlanabilir veyahut derleme zamanı veya çalışma zamanı ortamında yerleşik (*built-in*) olarak tanımlanabilir. Her iki fazda da bunlardan faydalanmak için modül sisteminin bunları yerleştirmesi ve ardından güvenilir konfigürasyon (*reliable configuration*) ve güçlü kapsülleme (*strong encapsulation*) sağlayacak şekilde birbirleriyle nasıl ilişki kurduklarını belirlemesi gerekir. +Bireysel modüller(*individual modules*), modül yapılarında (*module artifacts*) tanımlanabilir veyahut derleme zamanı veya çalışma zamanı ortamında yerleşik (*built-in*) olarak tanımlanabilir. Her iki fazda da bunlardan faydalanmak için modül sisteminin bunları yerleştirmesi ve ardından güvenilir konfigürasyon (*reliable configuration*) ve güçlü kapsülleme (*strong encapsulation*) sağlayacak şekilde birbirleriyle nasıl ilişki kurduklarını belirlemesi gerekir. ### 2.1 The module path (modül yolu) @@ -176,7 +178,7 @@ module com.foo.app { } {% endhighlight %} -Bu ilk uygulama modülü göz önüne alındığında, modül sistemi, bu bağımlılıkları yerine getirmek (*fulfill*) için ek gözlemlenebilir modüller (*observable modules*) yerleştirerek `requires` clause’larla ifade edilen bağımlılıkları çözer ve ardından her modülün her bağımlılığı yerine getirilene (karşılanana kadar) kadar bu modüllerin bağımlılıklarını vb. şeyleri çözer. Bu geçişli-kapatma (*transitive-closure*) hesaplamasının sonucu, başka bir modül tarafından yerine getirilen bir bağımlılığa sahip her modül için, ilk modülden ikinciye yönlendirilmiş bir kenar (*directed edge*) içeren bir modül grafiğidir (*module graph*). +Bu ilk uygulama modülü göz önüne alındığında, modül sistemi, bu bağımlılıkları yerine getirmek (*fulfill*) için ek gözlemlenebilir modüller (*observable modules*) yerleştirerek `requires` clause’larla ifade edilen bağımlılıkları çözer ve ardından her modülün her bağımlılığı yerine getirilene (karşılanana kadar) kadar bu modüllerin bağımlılıklarını, vb. şeyleri çözer. Bu geçişli-kapatma (*transitive-closure*) hesaplamasının sonucu, başka bir modül tarafından yerine getirilen bir bağımlılığa sahip her modül için, ilk modülden ikinciye yönlendirilmiş bir kenar (*directed edge*) içeren bir modül grafiğidir (*module graph*). Modül sistemi, `com.foo.app` modülü için bir modül grafiği oluşturmak amacıyla, `java.sql` modülünün bildirimini inceler: @@ -195,17 +197,17 @@ Ayrıca yukarıda gösterilen `com.foo.bar` modülünün ve ayrıca `org.baz.qux Tüm bu modül bildirimlerine dayanarak `com.foo.app` modülü için hesaplanan grafik aşağıdaki düğümleri (*nodes*) ve kenarları (*edges*) içerir: -
{% picture 2023-12-28-java-module-system/module-1.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-1.png --alt Java'da Modül Sistemi - Resolution (çözünme) --img width="100%" height="100%" %}
-Bu şekilde koyu mavi çizgiler, `requires` cümleciklerinde ifade edildiği gibi açık (*explicit*) bağımlılık ilişkilerini temsil ederken, açık mavi (aslında grimsi) çizgiler her modülün temel modül (*base module*) üzerindeki örtülü (*implicit*) bağımlılıklarını temsil eder. +Bu şekilde koyu mavi çizgiler, `requires` cümleciklerinde ifade edildiği gibi açık (*explicit*) bağımlılık ilişkilerini temsil ederken, açık mavi (daha çok grimsi) çizgiler her modülün temel modül (*base module*) üzerindeki örtülü (*implicit*) bağımlılıklarını temsil eder. ### 2.3 Readability (okunabilirlik) -Modül grafiğinde bir modül doğrudan diğerine bağlı/bağımlı olduğunda, ilk modüldeki kod, ikinci modüldeki türlere başvurabilecektir. Bu nedenle, ilk modülün ikinciyi okuduğunu veya eşdeğer olarak ikinci modülün birinci tarafından okunabilir olduğunu söylüyoruz. Dolayısıyla, yukarıdaki grafikte `com.foo.app` modülü `com.foo.bar` ve `java.sql` modüllerini okur, ancak `org.baz.qux`, `java.xml` veya `java.logging` modüllerini okumaz. `java.logging` modülü `java.sql` modülü tarafından okunabilir, ancak diğerleri tarafından okunamaz. (Her modül tanımı gereği kendini okur.) +Modül grafiğinde bir modül doğrudan diğerine bağlı/bağımlı olduğunda, ilk modüldeki kod, ikinci modüldeki türlere başvurabilecektir. Bu nedenle, ilk modülün ikinciyi okuduğunu veya eşdeğer olarak ikinci modülün birinci tarafından okunabilir olduğunu söylüyoruz. Dolayısıyla, yukarıdaki grafikte `com.foo.app` modülü, `com.foo.bar` ve `java.sql` modüllerini okur, ancak `org.baz.qux`, `java.xml` veya `java.logging` modüllerini okumaz. `java.logging` modülü `java.sql` modülü tarafından okunabilir, ancak diğerleri tarafından okunamaz. (Her modül tanımı gereği kendini okur.) Bir modül grafiğinde tanımlanan okunabilirlik ilişkileri **güvenilir konfigürasyonun** (*reliable configuration*) temelini oluşturur: Modül sistemi, her bağımlılığın tam olarak başka bir modül tarafından karşılanmasını, modül grafiğinin döngüsel olmamasını (*acyclic*), her modülün belirli bir paketi tanımlayan en fazla bir modülü okumasını ve aynı adlı paketleri (*identically-named packages*) tanımlayan modüllerin birbirine müdahale etmemesini sağlar. -Güvenilir konfigürasyon (*reliable configuration*) yalnızca daha güvenilir olmakla kalmaz; aynı zamanda daha hızlı da olabilir. Bir modüldeki kod, bir paketteki bir türe başvuruda bulunduğunda, o paketin ya o modülde ya da tam olarak o modül tarafından okunan modüllerden birinde tanımlanacağı garanti edilir. Belirli bir türün tanımını ararken, bu nedenle onu birden fazla modülde veya daha kötüsü tüm sınıf yolu (*class path*) boyunca aramaya gerek yoktur. +Güvenilir konfigürasyon (*reliable configuration*) yalnızca daha güvenilir olmakla kalmaz; aynı zamanda daha hızlı da olabilir. Bir modüldeki kod, bir paketteki bir türe başvuruda bulunduğunda, o paketin, ya o modülde, ya da tam olarak o modül tarafından okunan modüllerden birinde tanımlanacağı garanti edilir. Belirli bir türün tanımını ararken, bu nedenle onu birden fazla modülde veya daha kötüsü tüm sınıf yolu (*class path*) boyunca aramaya gerek yoktur. ### 2.4 Accessibility (erişilebilirlik) @@ -214,19 +216,19 @@ Bir modül grafiğinde tanımlanan okunabilirlik ilişkileri, modül deklarasyon * S'nin modülü T'nin modülünü okuyorsa ve * T'nin modülü T'nin paketini dışa aktarıyorsa (*export*). -Bu şekilde erişilemeyen modül sınırları (*module boundaries*) arasında başvurulan bir tür, `private` bir yöntem veya alanın (*field*) kullanılamaz olduğu gibi kullanılamaz: Bunu kullanmaya yönelik herhangi bir girişim, derleyici tarafından bir hatanın bildirilmesine veya Java sanal makinesi tarafından bir `IllegalAccessError` atılmasına veya *reflective* çalışma zamanı API'leri tarafından bir `IllegalAccessException` atılmasına neden olacaktır. Bu nedenle, bir tür `public` olarak bildirildiğinde bile, eğer paketi modül bildiriminde dışa aktarılmamışsa (yani *export* edilmemişse), yalnızca o modüldeki kodla erişilebilir olacaktır. +Bu şekilde erişilemeyen, modül sınırları (*module boundaries*) genelinde/boyunca başvurulan bir tür, `private` bir yöntem veya alanın (*field*) kullanılamaz olduğu gibi kullanılamaz: Bunu kullanmaya yönelik herhangi bir girişim, derleyici tarafından bir hatanın bildirilmesine veya Java sanal makinesi tarafından bir `IllegalAccessError` atılmasına veya *reflective* çalışma zamanı API'leri tarafından bir `IllegalAccessException` atılmasına neden olacaktır. Bu nedenle, bir tür `public` olarak bildirildiğinde bile, eğer paketi, modül bildiriminde dışa aktarılmamışsa (yani *export* edilmemişse), yalnızca o modüldeki kodla erişilebilir olacaktır. -Modül sınırları (*module boundaries*) boyunca başvurulan bir yöntem veya alan (*field*), bu anlamda çevreleyen türü (*enclosing type*) erişilebilirse ve üyenin kendisinin beyanı da erişime izin veriyorsa erişilebilir. +Modül sınırları (*module boundaries*) genelinde/boyunca başvurulan bir yöntem veya alan (*field*), bu anlamda çevreleyen türü (*enclosing type*) erişilebilirse ve üyenin (*member*) kendisinin beyanı da erişime izin veriyorsa erişilebilir. Yukarıdaki modül grafiği açısından güçlü kapsüllemenin (*strong encapsulation*) nasıl çalıştığını görmek için, her modülü dışa aktardığı (*exports* ettiği) paketlerle etiketliyoruz: -
{% picture 2023-12-28-java-module-system/module-2.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-2.png --alt Java'da Modül Sistemi - Accessibility (erişilebilirlik), exports clauses --img width="100%" height="100%" %}
-`com.foo.app` modülündeki kod, `com.foo.bar.alpha` paketinde bildirilen `public` türlere erişebilir çünkü `com.foo.app`, `com.foo.bar` modülüne bağımlı olduğundan ve dolayısıyla `com.foo.bar`, `com.foo.bar.alpha` paketini dışa aktardığından (yani *export* ettiği için) onu okur. Eğer `com.foo.bar` dahili bir `com.foo.bar.internal` paketi içeriyorsa, `com.foo.app` içindeki kod, `com.foo.bar` onu dışa aktarmadığından (*export* etmediğinden) bu paketteki hiçbir türe erişemez. `com.foo.app` içindeki kod, `org.baz.qux` paketindeki türlere başvuruda bulunamaz çünkü `com.foo.app`, `org.baz.qux` modülüne bağımlı değildir ve bu nedenle onu okumaz(okuyamaz). +`com.foo.app` modülündeki kod, `com.foo.bar.alpha` paketinde bildirilen `public` türlere erişebilir çünkü `com.foo.app`, `com.foo.bar` modülüne bağımlı olduğundan ve dolayısıyla `com.foo.bar`, `com.foo.bar.alpha` paketini dışa aktardığından (yani *export* ettiği için) onu okur. Eğer `com.foo.bar` dahili (*internal*) bir `com.foo.bar.internal` paketi içeriyorsa, `com.foo.app` içindeki kod, `com.foo.bar` onu dışa aktarmadığından (*export* etmediğinden) bu paketteki hiçbir türe erişemez. `com.foo.app` içindeki kod, `org.baz.qux` paketindeki türlere başvuruda bulunamaz çünkü `com.foo.app`, `org.baz.qux` modülüne bağımlı değildir ve bu nedenle onu okumaz(okuyamaz). ### 2.5 Implied readability (zımni/örtük/örtülü okunabilirlik) -Bir modül başka bir modül okuyorsa, bazı durumlarda mantıksal olarak diğer bazı modülleri de okuması gerekir. +Bir modül diğerini (yani başka bir modülü) okuyorsa, bazı durumlarda mantıksal olarak diğer bazı modülleri de okuması gerekir. Örneğin platformun `java.sql` modülü `java.logging` ve `java.xml` modüllerine bağımlıdır; bunun nedeni yalnızca bu modüllerdeki türleri kullanan uygulama kodunu içermesi değil, aynı zamanda imzaları bu modüllerdeki türlere başvuruda bulunan türleri tanımlamasıdır (*it defines types whose signatures refer to types in those modules*). @@ -269,7 +271,7 @@ module java.sql { `transitive` değiştiriciler, `java.sql` modülüne bağımlı herhangi bir modülün yalnızca `java.sql` modülünü değil aynı zamanda `java.logging` ve `java.xml` modüllerini de okuyacağı anlamına gelir. Bu nedenle, yukarıda gösterilen `com.foo.app` modülü için modül grafiği, bu modül tarafından ima edildiğinden `java.sql` modülüne yeşil kenarlarla bağlanan iki ek koyu mavi kenar içerir: -
{% picture 2023-12-28-java-module-system/module-3.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-3.png --alt Java'da Modül Sistemi - Implied readability (zımni/örtük/örtülü okunabilirlik), requires transitive clauses --img width="100%" height="100%" %}
`com.foo.app` modülü artık `java.logging` ve `java.xml` modüllerinin dışa aktarılan (*export* edilen) paketlerindeki tüm `public` türlere erişen kodu içerebilir, her ne kadar deklarasyonunda bu modüllerden bahsedilmese de. @@ -277,37 +279,37 @@ Genel olarak, eğer bir modül, imzası ikinci modüldeki bir pakete başvuruda ## 3 COMPATIBILITY & MIGRATION (uyumluluk ve migrasyon/taşıma) -Şu ana kadar modülleri sıfırdan nasıl tanımlayacağımızı, bunları modül artifekleri halinde nasıl paketleyeceğimizi ve bunları platformda yerleşik olan veya artifeklerde tanımlanan diğer modüllerle birlikte nasıl kullanacağımızı gördük. +Şu ana kadar modülleri sıfırdan nasıl tanımlayacağımızı, modül artifekleri halinde nasıl paketleyeceğimizi ve platformda yerleşik olan veya artifeklerde tanımlanan diğer modüllerle birlikte nasıl kullanacağımızı gördük. -Çoğu Java kodu, elbette, modül sisteminin tanıtımından önce yazılmıştır ve bugün olduğu gibi, değişmeden çalışmaya devam etmelidir. Bu nedenle modül sistemi, platformun kendisi modüllerden oluşsa bile, sınıf yolunda (*class path*) JAR dosyalarından oluşan uygulamaları derleyebilir ve çalıştırabilir. Ayrıca mevcut uygulamaların esnek ve kademeli bir şekilde modüler forma taşınmasını da sağlar. +Çoğu Java kodu, elbette, modül sisteminin tanıtımından önce yazılmıştır ve bugün olduğu gibi, değişmeden çalışmaya devam etmelidir. Bu nedenle modül sistemi, platformun kendisi modüllerden oluşsa bile, sınıf yolunda (*class path*) JAR dosyalarından oluşan uygulamaları derleyebilir ve çalıştırabilir. Ayrıca mevcut uygulamaların esnek ve kademeli bir şekilde modüler forma taşınmasını/migrasyonunu da sağlar. ### 3.1 The unnamed module (isimsiz/adlandırılmamış modül) -Bilinen hiçbir bir modülde paketi tanımlanmayan bir türün yüklenmesi için bir talepte bulunulursa, modül sistemi onu sınıf yolundan (*class path*) yüklemeye çalışacaktır. Bu başarılı olursa, her türün bir modülle ilişkili olmasını sağlamak için tür, isimsiz modül (*unnamed module*) olarak bilinen özel bir modülün üyesi olarak kabul edilir. *unnamed* modül, yüksek düzeyde, mevcut isimsiz paket (*[unnamed package](https://docs.oracle.com/javase/specs/jls/se8/html/jls-7.html#jls-7.4.2)*) kavramına benzer. Diğer tüm modüllerin elbette isimleri vardır, dolayısıyla bundan sonra bunlara isimli modüller (*named module*) diyeceğiz. +Paketi bilinen herhangi bir modülde tanımlanmayan bir türün, yüklenmesi için bir talepte bulunulursa, modül sistemi onu sınıf yolundan (*class path*) yüklemeye çalışacaktır. Bu başarılı olursa, her türün bir modülle ilişkili olmasını sağlamak için, tür, isimsiz modül (*unnamed module*) olarak bilinen özel bir modülün üyesi olarak kabul edilir. İsimsiz modül (*unnamed module*), yüksek düzeyde, mevcut olan isimsiz paket (*[unnamed package](https://docs.oracle.com/javase/specs/jls/se8/html/jls-7.html#jls-7.4.2)*) kavramına benzer. Diğer tüm modüllerin elbette isimleri vardır, dolayısıyla bundan sonra bunlara isimli/adlandırılmış modüller (*named module*) diyeceğiz. -*unnamed* modül diğer tüm modülleri okur. Sınıf yolundan (*class path*’den) yüklenen herhangi bir türdeki kod, böylece diğer tüm okunabilir modüllerin dışa aktarılan (*exported*) türlerine erişebilecektir; bunlar varsayılan olarak tüm *named* yerleşik platform modüllerini içerecektir. Bu nedenle, Java SE 8 üzerinde derleyen ve çalışan mevcut bir sınıf yolu (*class-path*) uygulaması, yalnızca standart, kullanımdan kaldırılmamış (*non-deprecated*) Java SE API'lerini kullandığı sürece Java SE 9 üzerinde tam olarak aynı şekilde derlenecek ve çalışacaktır. +İsimsiz modül (unnamed module) diğer tüm modülleri okur. Sınıf yolundan (*class path*’den) yüklenen herhangi bir türdeki kod, böylece diğer tüm okunabilir modüllerin dışa aktarılan (*export* edilen) türlerine erişebilecektir; bunlar varsayılan olarak tüm adlandırılmış (*named*) yerleşik platform modüllerini içerecektir. Bu nedenle, Java SE 8 üzerinde derlenen ve çalışan mevcut bir sınıf yolu (*class-path*) uygulaması, yalnızca standart, kullanımdan kaldırılmamış (*non-deprecated*) Java SE API'lerini kullandığı sürece Java SE 9 üzerinde tam olarak aynı şekilde derlenecek ve çalışacaktır. -*unnamed* modül tüm paketlerini dışa aktarır (*export* eder). Bu, aşağıda göreceğimiz gibi esnek migrasyona/taşıma (*flexible migration*) olanak sağlar. Ancak bu, *named* modülündeki kodun *unnamed* modülündeki türlere erişebileceği anlamına gelmez. Aslında bir *named* modülü, *unnamed* modülüne bağımlılık bile beyan edemez. Bu kısıtlama kasıtlıdır, çünkü *named* modüllerinin sınıf yolunun (*class path*) keyfi içeriğine bağlı/bağımlı olmasına izin vermek güvenilir konfigürasyonu (*reliable configuration*) imkansız hale getirecektir. +İsimsiz modül (unnamed module) tüm paketlerini dışa aktarır (*export* eder). Bu, aşağıda göreceğimiz gibi esnek migrasyona/taşımaya (*flexible migration*) olanak sağlar. Ancak bu, adlandırılmış modüldeki (*named module*) kodun adlandırılmamış modüldeki (*unnamed module*) türlere erişebileceği anlamına gelmez. Aslında bir adlandırılmış modül (*named module*), adlandırılmamış bir modüle (*unnamed module*) bağımlılık bile beyan edemez. Bu kısıtlama kasıtlıdır, çünkü adlandırılmış modüllerin (*named module*), sınıf yolunun (*class path*'in) keyfi içeriğine bağlı/bağımlı olmasına izin vermek, güvenilir konfigürasyonu (*reliable configuration*) imkansız hale getirecektir. -Bir paket hem *named* modülde hem de *unnamed* modülde tanımlanmışsa, *unnamed* modüldeki paket dikkate alınmaz. Bu, sınıf yolunun (*class-path*’in) kaosu karşısında bile güvenilir yapılandırmayı (*reliable configuration*) korur, hâlâ her modülün belirli/verilen bir paketi tanımlayan en fazla bir modülü okumasını sağlar. Yukarıdaki örneğimizde, sınıf yolundaki (*class-path*’deki) bir JAR dosyası, `com/foo/bar/alpha/AlphaFactory.class` adında bir sınıf (*class*) dosyası içeriyorsa, `com.foo.bar.alpha` paketi `com.foo.bar` modülü tarafından dışa aktarıldığından (yani `export` edildiğinden) bu dosya hiçbir zaman yüklenmeyecektir. +Bir paket hem adlandırılmış (*named*) modülde hem de adlandırılmamış (*unnamed*) modülde tanımlanmışsa, adlandırılmamış (*unnamed*) modüldeki paket dikkate alınmaz. Bu, hâlâ her modülün belirli bir paketi tanımlayan en fazla bir modülü okumasını sağlarken, sınıf yolunun (*class-path*’in) kaosu karşısında bile güvenilir yapılandırmayı (*reliable configuration*) korur. Yukarıdaki örneğimizde, sınıf yolundaki (*class-path*’deki) bir JAR dosyası, `com/foo/bar/alpha/AlphaFactory.class` adında bir sınıf (*class*) dosyası içeriyorsa, `com.foo.bar.alpha` paketi `com.foo.bar` modülü tarafından dışa aktarıldığından (yani `export` edildiğinden), bu dosya hiçbir zaman yüklenmeyecektir. ### 3.2 Bottom-up migration (aşağıdan yukarı migrasyon/taşıma) -Sınıf yolundan (*class-path*’den) yüklenen türlerin *unnamed* modülün üyeleri olarak işlenmesi, mevcut bir uygulamanın bileşenlerini JAR dosyalarından modüllere inkremental, aşağıdan-yukarı (*bottom-up* fashion) bir şekilde taşımamıza (*migrate*) olanak tanır. +Sınıf yolundan (*class-path*’den) yüklenen türlerin adlandırılmamış modülün (*unnamed module*) üyeleri olarak ele alınması/işlenmesi, mevcut bir uygulamanın bileşenlerini, JAR dosyalarından modüllere inkremental, (yani) aşağıdan-yukarı (*bottom-up* fashion) bir şekilde taşımamıza (*migrate*) olanak tanır. -Örneğin, yukarıda gösterilen uygulamanın başlangıçta Java SE 8 için, sınıf yoluna (*class path*) yerleştirilen bir dizi benzer şekilde adlandırılmış JAR dosyaları olarak oluşturulduğunu varsayalım. Eğer bunu Java SE 9'da olduğu gibi çalıştırırsak, JAR dosyalarındaki türler *unnamed* modülde tanımlanacaktır. Bu modül, tüm yerleşik platform modülleri de dahil olmak üzere diğer tüm modülleri okuyacaktır; Basitlik açısından, bunların daha önce gösterilen `java.sql`, `java.xml`, `java.logging` ve `java.base` modülleriyle sınırlı olduğunu varsayalım. Böylece modül grafiğini elde ederiz: +Örneğin, yukarıda gösterilen uygulamanın başlangıçta Java SE 8 için, sınıf yoluna (*class path*) yerleştirilen bir dizi benzer şekilde adlandırılmış JAR dosyaları olarak oluşturulduğunu varsayalım. Eğer bunu, Java SE 9'da olduğu gibi çalıştırırsak, JAR dosyalarındaki türler, adlandırılmamış modülde (*unnamed module*) tanımlanacaktır. Bu modül, tüm yerleşik platform modülleri de dahil olmak üzere diğer tüm modülleri okuyacaktır; Basitlik açısından, bunların daha önce gösterilen `java.sql`, `java.xml`, `java.logging` ve `java.base` modülleriyle sınırlı olduğunu varsayalım. Böylece (aşağıdaki) modül grafiğini elde ederiz: -
{% picture 2023-12-28-java-module-system/module-4.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-4.png --alt Java'da Modül Sistemi - Bottom-up migration (aşağıdan yukarı migrasyon/taşıma) --img width="100%" height="100%" %}
`org-baz-qux.jar`’ı hemen *named* bir modüle dönüştürebiliriz, çünkü onun diğer iki JAR dosyasındaki herhangi bir türe başvuruda bulunmadığını biliyoruz, bu nedenle *named* bir modül olarak *unnamed* modülde geride bırakılacak türlerin hiçbirine başvuruda/atıfta bulunmayacaktır. (Bunu tesadüfen de olsa orijinal örnekten biliyoruz, ancak zaten bilmiyorsak, **[jdeps](https://docs.oracle.com/en/java/javase/11/tools/jdeps.html)** gibi bir araç yardımıyla keşfedebiliriz. ) `org.baz.qux` için bir modül deklarasyonu yazıyoruz, bunu modülün kaynak koduna ekliyoruz, derliyoruz ve sonucu modüler bir JAR dosyası olarak paketliyoruz. Daha sonra o JAR dosyasını modül yoluna (*module path*) yerleştirirsek ve diğerlerini sınıf yolunda (*class path*) bırakırsak, geliştirilmiş modül grafiğini elde ederiz. -
{% picture 2023-12-28-java-module-system/module-5.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-5.png --alt Java'da Modül Sistemi - Bottom-up migration (aşağıdan yukarı migrasyon/taşıma) --img width="100%" height="100%" %}
`com-foo-bar.jar` ve `com-foo-app.jar` içindeki kod çalışmaya devam ediyor çünkü *unnamed* modül, artık yeni `org.baz.qux` modülünü de içeren her *named* modülü okuyor. `com-foo-bar.jar`'ı ve ardından `com-foo-app.jar`'ı modüler hale getirmek için benzer şekilde ilerleyebiliriz, sonunda daha önce gösterilerek amaçlanan modül grafiği elde edilir: -
{% picture 2023-12-28-java-module-system/module-6.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-6.png --alt Java'da Modül Sistemi - Bottom-up migration (aşağıdan yukarı migrasyon/taşıma) --img width="100%" height="100%" %}
Orijinal JAR dosyalarındaki türler hakkında ne yaptığımızı bilerek, elbette üçünü de tek bir adımda modüler hale getirebiliriz. Bununla birlikte, `org-baz-qux.jar` bağımsız olarak, belki de tamamen farklı bir ekip veya organizasyon tarafından korunursa, o zaman diğer iki bileşenden önce modüler hale getirilebilir ve aynı şekilde `com-foo-bar.jar`, `com-foo-app.jar`’dan önce modüler hale getirilebilir. @@ -321,27 +323,27 @@ O halde bir şekilde `org-baz-qux.jar`’ın *named* bir modül olarak görünme Bunun yerine `org-baz-qux.jar`'ı, sınıf yolu (*class path*) yerine modül yoluna (*module path*) değiştirilmeden yerleştirerek otomatik bir modül (*automatic module*) olarak işleyebiliriz. Bu, adı `org.baz.qux` olan, JAR dosyasından türetilen bir gözlemlenebilir modül (*observable module*) tanımlayacaktır, böylece diğer otomatik olmayan modüller (*non-automatic modules*) alışılmış şekilde ona bağlı olabilir/bağlanabilir: -
{% picture 2023-12-28-java-module-system/module-7.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-7.png --alt Java'da Modül Sistemi - Automatic modules (otomatik modüller) --img width="100%" height="100%" %}
Bir otomatik modül (*automatic module*), bir modül deklarasyonuna sahip olmadığından örtülü (*implicitly*) olarak tanımlanan *named* bir modüldür. Bunun aksine, tipik bir *named* modül, bir modül bildirimiyle açıkça (*explicitly*) tanımlanır; bundan sonra bunlara **açık modüller** (*explicit modules*) olarak değineceğiz. Bir otomatik modülün (*automatic module*) hangi diğer modüllere bağlı olabileceğini önceden söylemenin pratik bir yolu yoktur. Bu nedenle, bir modül grafiği çözümlendikten sonra, ister otomatik (*automatic*) ister açık (*explicit*) olsun, diğer tüm *named* modülleri okumak için bir otomatik modül (*automatic module*) yapılır. -
{% picture 2023-12-28-java-module-system/module-8.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-8.png --alt Java'da Modül Sistemi - Automatic modules (otomatik modüller) --img width="100%" height="100%" %}
(Bu yeni okunabilirlik kenarları (*readability edges*) modül grafiğinde döngüler (*cycles*) yaratır ve bu da mantık yürütmeyi biraz daha zorlaştırır, ancak biz bunları daha esnek migrasyona/taşımaya (*more-flexible migration*) olanak sağlamanın tolere edilebilir ve genellikle geçici bir sonucu olarak görüyoruz.) Benzer şekilde, bir otomatik modüldeki (*automatic module*) paketlerden hangisinin diğer modüller tarafından veya hala sınıf yolunda (*class path*) bulunan sınıflar tarafından kullanılmak üzere tasarlandığını söylemenin pratik bir yolu yoktur. Bu nedenle, otomatik bir modüldeki (*automatic module*) her paket, gerçekte yalnızca dahili kullanım (*internal use*) için tasarlanmış olsa bile dışa aktarılmış (*export* edilmiş) olarak kabul edilir: -
{% picture 2023-12-28-java-module-system/module-9.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-9.png --alt Java'da Modül Sistemi - Automatic modules (otomatik modüller) --img width="100%" height="100%" %}
Son olarak, otomatik bir modüldeki (*automatic module*) dışa aktarılan (*export* edilen) paketlerden birinin, imzası başka bir otomatik modülde tanımlanan bir türe başvuruda bulunan bir tür içerip içermediğini söylemenin pratik bir yolu yoktur. Örneğin; önce `com.foo.app`’i modüler hale getirirsek ve hem `com.foo.bar` hem de `org.baz.qux`’u otomatik modüller (*automatic modules*) olarak işlersek/ele alırsak, o zaman aşağıdaki grafiği elde ederiz -
{% picture 2023-12-28-java-module-system/module-10.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-10.png --alt Java'da Modül Sistemi - Automatic modules (otomatik modüller) --img width="100%" height="100%" %}
Karşılık gelen her iki JAR dosyasındaki tüm sınıf dosyalarını okumadan, `com.foo.bar`’daki "`public`" bir türün, dönüş tipi `org.baz.qux`'ta tanımlanan "`public`" bir yöntemi bildirip bildirmediğini bilmek imkansızdır. Bu nedenle otomatik bir modül (*automatic module*), diğer tüm otomatik modüllere (*automatic module*) zımni/örtük okunabilirlik (*implied readability*) sağlar: -
{% picture 2023-12-28-java-module-system/module-11.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-11.png --alt Java'da Modül Sistemi - Automatic modules (otomatik modüller) --img width="100%" height="100%" %}
Artık `com.foo.app` içindeki kod `org.baz.qux` içindeki türlere erişebilir, ancak aslında öyle olmadığını biliyoruz. @@ -353,7 +355,7 @@ Mevcut JAR dosyalarının çoğu otomatik modül (*automatic modules*) olarak ku Bazı JAR dosyaları otomatik modüller (*automatic modules*) olarak kullanılamadığında bile migrasyonu etkinleştirmek için, otomatik modüllerin (*automatic modules*) açık modüllerdeki (*explicit modules*) kod ile hâlâ sınıf yolunda (*class path*) bulunan kod arasında köprü görevi görmesini sağlıyoruz: Diğer tüm *named* modüllerin okunmasına ek olarak, *unnamed* modülün okunması için bir otomatik modül (*automatic module*) de yapılır. Uygulamamızın orijinal sınıf yolu (*class path*), örneğin, aynı zamanda `org-baz-fiz.jar` ve `org-baz-fuz.jar` JAR dosyalarını da içerseydi, o zaman (aşağıdaki) grafiğe sahip olurduk. -
{% picture 2023-12-28-java-module-system/module-12.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-12.png --alt Java'da Modül Sistemi - Bridges to the class path (sınıf yoluna köprüler) --img width="100%" height="100%" %}
*unnamed* modül, daha önce de belirtildiği gibi tüm paketlerini dışa aktarır (*export* eder), böylece otomatik modüllerdeki (*automatic modules*) kod, sınıf yolundan (*class path*) yüklenen herhangi bir `public` türe erişebilecektir. @@ -378,7 +380,7 @@ deklarasyonuna sahip gözlemlenebilir bir modülde (*observable module*) bir MyS `java.sql` modülünün bu sürücüyü (*driver*) kullanabilmesi için, `ServiceLoader` sınıfının sürücü (*driver*) sınıfını, yansıma (*reflection*) yoluyla başlatabilmesi (*instantiate* edebilmesi) gerekir; bunun gerçekleşmesi için modül sisteminin sürücü (*driver*) modülünü modül grafiğine eklemesi ve bağımlılıklarını çözmesi gerekir, böylece: -
{% picture 2023-12-28-java-module-system/module-13.png --alt Java'da Modül Sistemi --img width="100%" height="100%" %}
+
{% picture 2023-12-28-java-module-system/module-13.png --alt Java'da Modül Sistemi - SERVICES (servisler/hizmetler) --img width="100%" height="100%" %}
Bunu başarmak için modül sistemi, önceden-çözümlenmiş modüller aracılığıyla servislerin herhangi bir kullanımını (*uses of services*) tanımlayabilmeli ve ardından gözlemlenebilir modüller (*observable modules*) kümesi içinden sağlayıcıların (*providers*) yerini tespit edip, çözebilmelidir.