Kotlin'in en güçlü noktalarından biri aynı zamanda zayıflığı da olabilir. Bugün veri sınıflarından ve aynı şekilde Java kayıtlarından bahsettiğimizde, en azından tanıdığım birçok kişinin yaptığı gibi, standart kodun tamamen ortadan kaldırılmasına odaklanma eğilimindeyiz. Ortak kod, çağlar boyunca geliştiricilerin canını sıkan bir şey olmuştur. Sadece Java'da değil, diğer dillerde de var. Herhangi bir şekilde veri erişim nesneleri oluşturmayı düşünürsek, bunu Kotlin'de mi, Java'da mı yoksa başka bir dilde mi yaptığımızın pek bir önemi yok.
Aynı süreci sıklıkla tekrarlıyoruz: depo oluşturma, servis ve kontrolör. Yaptığımız şeylerin çoğu hala standart bir şey. Bununla birlikte standart kod, veri sınıfları veya Java kayıtları oluşturma kararının bir parçası olabilir; yazılım mühendisliğinin daha önemli bir paradigması, bu tür veri yapılarını oluşturmanın asıl odak noktasıydı.
Her şey değişmezliğe veya her halükarda bunun olasılığına bağlı. Zamanı geri alalım ve bir noktada farklı şeyleri belirteceğimiz veri yapıları oluşturmaya başladığımız 1995 yılına geri dönelim. Alanları, alıcıları, ayarlayıcıları, özellikleri, erişimcileri, nitelikleri ve parametreleri, argümanlarımızı yöntemlere, işlevlere veya yapıcılara aktarabilecek şekilde tanımlayacağız. Bu bölüm için şunları yapacağız: 80'lerin ortasındaki The Golden Girls dizisinin karakterlerini kullanan eğlenceli programlar. Bunu söyledikten sonra, bir sınıfın yaklaşık 15 yıl boyunca nasıl görüneceğine bakalım:
public class GoldenGirlsJava { public String goldenGirl1; private final String goldenGirl2; private final String goldenGirl3; private final String goldenGirl4; public GoldenGirlsJava() { this.goldenGirl1 = "Dorothy Zbornak"; this.goldenGirl2 = "Rose Nylund"; this.goldenGirl3 = "Blanche Devereaux"; this.goldenGirl4 = "Sophia Petrillo"; } public GoldenGirlsJava( String goldenGirl1, String goldenGirl2, String goldenGirl3, String goldenGirl4 ) { this.goldenGirl1 = goldenGirl1; this.goldenGirl2 = goldenGirl2; this.goldenGirl3 = goldenGirl3; this.goldenGirl4 = goldenGirl4; } public String getGoldenGirl1() { return goldenGirl1; } public void setGoldenGirl1(String goldenGirl1) { this.goldenGirl1 = goldenGirl1; } public String getGoldenGirl2() { return goldenGirl2; } public String getGoldenGirl3() { return goldenGirl3; } public String getGoldenGirl4() { return goldenGirl4; } @Override public String toString() { return "GoldenGirlsJava{" + "goldenGirl1='" + goldenGirl1 + '\'' + ", goldenGirl2='" + goldenGirl2 + '\'' + ", goldenGirl3='" + goldenGirl3 + '\'' + ", goldenGirl4='" + goldenGirl4 + '\'' + '}'; } }
Bu, yalnızca iki kurucu oluşturmak için yazılacak muazzam miktarda koddu. Hashcode ve equals her durumda zorunlu olmasa da, neredeyse her zaman daha genel bir kurucunun yanında argümansız bir kurucu uygulamak zorunda kaldık. Tüm bu standart kodu oluşturmanın iyi yanı, bayt koduna derledikten sonra her şeyin nasıl görüneceğini çok net bir şekilde biliyor olmamızdı.
Bununla birlikte, her halükarda, ortak kod birçok geliştirici için her zaman tartışmalı bir konuydu ve bu nedenle 2009'da lombok ortaya çıktı ve veri yapıları oluşturma şeklimizde devrim yarattı. Bir açıklama işlemcisi kullanma ve sınıflarımız için ihtiyaç duyduğumuz nitelikleri verecek belirli açıklamaları yorumlama kavramını tanıttı ve böylece lombok açıklamalı bir sınıf şöyle görünecektir:
@Getter @Setter @AllArgsConstructor @ToString public class GoldenGirlsLombok { public String goldenGirl1; private final String goldenGirl2; private final String goldenGirl3; private final String goldenGirl4; public GoldenGirlsLombok() { this.goldenGirl1 = "Dorothy Zbornak"; this.goldenGirl2 = "Rose Nylund"; this.goldenGirl3 = "Blanche Devereaux"; this.goldenGirl4 = "Sophia Petrillo"; } }
Ve bir süreliğine insanlar Lombok'tan çok memnundu! Sonunda tüm bu standart kodları oluşturma zorunluluğunun ağırlığı ortadan kalktı. Ancak yeni bir oyuncunun gelmesiyle bu düşüş yaklaşık 7 yıl sürdü ve bu sefer yazılım geliştirme sektörünün beklemediği bir şey oldu. Adı Kotlin'di ve 2016'da veri sınıflarının hemen tanıtılmasıyla ilk kez sahneye çıktı. Kotlin'deki altın kızlar uygulamamız artık şöyle görünecek:
data class GoldenGirls( var goldenGirl1: String = "Dorothy Zbornak", private val goldenGirl2: String = "Rose Nylund", private val goldenGirl3: String = "Blanche Devereaux", private val goldenGirl4: String = "Sophia Petrillo" )
Kotlin yavaş yavaş hayran toplamaya başlasa da Java piyasada başka bir şeyin olduğunu fark etti ve bu taraftaki bazı gelişmeler, yapım aşamasında olan ancak bir süredir arka planda bırakılan Loom projesi gibi ivme kazanmaya başladı. Bu nedenle, Java 14'ün 20202'de piyasaya sürülmesiyle Java, Java kayıtlarını tanıttı ve Java'daki veri yapıları artık şöyle görünecek:
public record GoldenGirlsRecord( String goldenGirl1, String goldenGirl2, String goldenGirl3, String goldenGirl4 ) { public GoldenGirlsRecord() { this( "Dorothy Zbornak", "Rose Nylund", "Blanche Devereaux", "Sophia Petrillo" ); } }
Ve bugüne kadar kod basitleştirme ve kod azaltma devam edecek gibi görünüyor. Ancak standart kodun azaltılmasıyla birlikte alanlar, alıcılar, ayarlayıcılar, özellikler, erişimciler, nitelikler ve parametreler kavramları çok daha az görsel hale geldi ve zihinlerimizde haritalanması daha az kolay hale geldi. Beğensek de beğenmesek de, bu kavramlar hala JVM'nin bayt koduyla kodu nasıl düzenlediği ve düzenlediği ile ilgilidir. Ancak kodun aşırı basitleştirilmesi aslında kodun okunmasını kolaylaştırmakla ilgilidir ve veri sınıfları ve Java kayıtları söz konusu olduğunda fikir aynı zamanda veri yapıları oluşturmaktır. değişmez veya kısmen değişmez.
Java kayıtları, içerdiği tüm değerlerin veya içerdiği referansların değiştirilememesi anlamında gerçekten değişmezdir. Kotlin veri sınıfları da aynı nedenlerden dolayı gerçekten değişmez olabilir, ancak geliştiricilere karmaşık ve en kötüsü, değiştirilebilir kod oluşturma izni veren bir şekilde buna sahip değiller. Büyük ölçüde ek açıklamalara dayanan Spring Framework gibi çerçevelerle çalışmak. İşte bir örnek:
@Entity @Table(name = "shelf_case") data class Case( @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) val id: Long?, var designation: String?, var weight: Long? ) { constructor() : this(0L, null, null) override fun toString(): String { return super.toString() } }
Bu örnek iyi çalışıyor. Şüphelenmeyen bir göz için burada pek özel bir durum yok. Bu, Kotlin'de Java'da olduğu gibi çalışır. Şimdi benzer bir örneğe bakalım, ancak bu sefer Jackson'ın açıklamalarıyla:
data class AccountNumbersPassiveDto( @NotNull val accountNumberLong: Long?, val accountNumberNullable: Long?, @DecimalMax(value = "10") @DecimalMin(value = "5") val accountNumber: BigDecimal, val accountNumberEven: Int, val accountNumberOdd: Int, @Positive val accountNumberPositive: Int, @Negative val accountNumberNegative: Int, @DecimalMax(value = "5", groups = [LowProfile::class]) @DecimalMax(value = "10", groups = [MiddleProfile::class]) @DecimalMax(value = "15", groups = [HighProfile::class]) @DecimalMax(value = "20") val accountNumberMaxList:Int )
Bu örnek başarısız olacaktır ve bunun nedeni Kotlin'de derleyiciye açıklamamızın tam olarak nereye uygulanmasını istediğimizi söylemenin bir yolu olmamasıdır. Jakarta kalıcılık ek açıklaması olan @Entity
ek açıklamasını içeren önceki örnekte, ek açıklamalar alanlara doğru şekilde uygulanmıştır. Eğer bu kodu kaynak koda dönüştürürsek şunu bulacağız:
public final class Case { @Id @GeneratedValue( strategy = GenerationType.SEQUENCE ) @Nullable private final Long id; @Nullable private String designation; @Nullable private Long weight;
Ancak jakarta doğrulama örneği olan ikincisi için şunu buluyoruz:
public final class AccountNumbersPassiveDto { @Nullable private final Long accountNumberLong; @Nullable private final Long accountNumberNullable; @NotNull private final BigDecimal accountNumber; private final int accountNumberEven; private final int accountNumberOdd;
Bu, AccountNumbersDto
alanlarındaki bu ek açıklamalardan etkilenmediği anlamına gelir. İlk örnekte şanslıydık. Aslında başarısız da olabilir. Ek açıklamamızın nereye gitmesi gerektiğini belirlemek için Kotlin bize site hedeflerini herhangi bir ek açıklamaya önek olarak kullanma olanağı verir. Şart elbette şartların sağlanmasıdır. Bu durumda, bunu düzeltmenin bir yolu, tüm ek açıklamaların önüne şu şekilde @field
eklemektir:
data class AccountNumbersPassiveDto( @field:NotNull val accountNumberLong: Long?, val accountNumberNullable: Long?, @field:DecimalMax(value = "10") @field:DecimalMin(value = "5") val accountNumber: BigDecimal, val accountNumberEven: Int, val accountNumberOdd: Int, @field:Positive val accountNumberPositive: Int, @field:Negative val accountNumberNegative: Int, @field:DecimalMax(value = "5", groups = [LowProfile::class]) @field:DecimalMax(value = "10", groups = [MiddleProfile::class]) @field:DecimalMax(value = "15", groups = [HighProfile::class]) @field:DecimalMax(value = "20") val accountNumberMaxList:Int )
Şimdi ortaya çıkan bayt kodunu IntelliJ kullanarak kaynak koda dönüştürmeye çalışırsak, bunun Java'da şu kodla sonuçlandığını göreceğiz:
public final class AccountNumbersPassiveDto { @NotNull @Nullable private final Long accountNumberLong; @Nullable private final Long accountNumberNullable; @DecimalMax("10") @DecimalMin("5") @org.jetbrains.annotations.NotNull
Bu, ek açıklamaların alana uygulandığı ve kodumuzun olması gerektiği gibi çalıştığı anlamına gelir.
Bu noktada muhtemelen uzun süredir Java üzerinde çalışan kişilerin Kotlin'e uyum sağlama konusunda herhangi bir sorun yaşamayacağını tahmin edebilirsiniz çünkü hepimiz alanların, parametrelerin, özelliklerin vb. ne olduğunu biliyoruz. Bugün gözlemlediğimiz ve buna da şahit olduğum şey, kod sadeleştirmesinin geri tepme potansiyeli varmış gibi görünüyor. Bazı projelerde veya modüllerde ek açıklamaların neden işe yaramadığını anlamaya çalışırken projelerde harcanan zamanın farkına vardığım pek çok durum oldu. Ve bunların hepsi kullanım alanı hedeflerinden faydalanmamaktan kaynaklanıyor gibi görünüyor.
Büyük olasılıkla teorim, yeni nesil geliştiricilerin muhtemelen benim neslimin karmaşık olduğunu düşünmediği ve içgüdüsel olarak öğrendiği şeylere gerçekten karmaşık materyaller olarak bakacağıdır. Kullanım sitesi hedeflerinde durum böyledir. Bunlar eskiden çok kolay görselleştirebileceğimiz şeylerdi. Ancak günümüzde bu konuda ortaya çıkan kafa karışıklığı, bazı durumlarda projelerin zamanında geliştirilmesini geciktiriyor gibi görünüyor. Elbette genelleme yapamam ama Java kayıtları ve veri sınıflarında hem iyi hem de kötü potansiyel var. Veri sınıflarının ve kayıtların geleceğimizi nasıl şekillendireceğini söylemek zor, ancak açık olan bir şey var ki, bu sorun nedeniyle diğer çerçeveler Ktor'da olduğu gibi tamamen açıklamasız hale gelme konusunda iddialı.
Bununla ilgili belgeleri Scribed: Fields-in-Java-and-Kotlin-and-What-to-Expect ve ayrıca slayt paylaşımında: field-in-java-and-kotlin-and-what-to-expect üzerinde belgeler oluşturdum.
Verdiğim örnekleri GitHub'da da bulabilirsiniz. Altın kızlar örneğini burada bulabilirsiniz: jeorg-kotlin-test-drives ve Jakarta kalıcılığı ve doğrulama ek açıklamaları örneklerini burada bulabilirsiniz: https://github.com/jesperancinha/jeorg-spring-master-test-drives .
Son olarak YouTube'da bununla ilgili bir video da hazırladım, buradan göz atabilirsiniz:
Burada da yayınlandı.