Již před dávnými léty, kdy vypukl JVM-language boom, jsem se doslova musel smát, když jsem se (pocitově) každých 14 dnů dočetl o novém supr dupr programovacím jazyku pro JVM, který zřejmě má být ten nejlepší a říkal jsem si, proč doprčic potřebujeme něco dalšího, vždyť Scala již vyřešila všechny naše problémy, nebo ne? 🙂 Mou pozornost upoutalo nedávné prohlášení Googlu, který oznámil Kotlin jako oficiálně podporovaný jazyk pro Android a dále moc hezký článek Mika Hearna o tom, proč se právě Kotlin stal jeho dalším programovacím jazykem.

Jak se v Mikově článku dočteme, Scala vznikla na akademické půdě pokrývajíc akademické potřeby, kdežto Kotlin (vyvíjený firmou Jetbrains) na půdě programátorského průmyslu pokrývajíc potřeby ryze praktických programátorů. Zatímco Scala docela znatelně tlačí funkcionální koncepty, Kotlin na mě působí jako pokus o vyváženost stručnosti a čitelnosti kódu. Pro ty, kteří si myslí, že funkcionální paradigma je všespásné, bych řekl, že pro některé use-casy je velmi užitečné, ale pro velkou část praktických problémů to odpovědí rozhodně není.

Asi z mého pohledu nejzajímavější vlastností Kotlinu je jeho způsob, jakým se pokouší vypořádat s NullPointerException. Kotlin rozlišuje každý datový typ na 2 verze: takový, který nemůže byt null a druhý, který null být může. Následně kontroluje již při překladu, jestli jsou vaše volání null-safe. Tento přístup docela mění programátorův pohled na svůj kód a doslova ho při každé deklaraci nutí položit si otázku “Může tohle být null?”. Kdyby Java, kde každý objektový typ být null může, vynucovala null-checky, asi by všude musely být samé ify, což by přehlednost kódu úplně zničilo, a proto Kotlin zavedl svůj “otazník”, aby se s tímto docela elegantně vypořádal. Dobrá věc u safe-call nebo elvis-operátoru je, že se s ním dá docela pěkně refaktorovat, což umožní odstranit nadbytečné if bloky a dle mého názoru zlepší i čitelnost kódu.

Kotlin a Spring Boot

Ideálním způsobem, jak si nějaký nový jazyk vyzkoušet, je zkusit si v něm něco napsat. Mám tady u sebe pár soukromých (což znamená, že budu muset kód trochu obfuskovat 🙂 ) Spring Boot aplikací, tak jsem se rozhodl, že si jednu malou z nich zkusím přepsat do Kotlinu a uvidíme, jak to půjde. Nejdříve jsem musel upravit svůj pom.xml, ať můžu používat jak Kotlin, tak Javu dohromady, což se mi nakonec po troše trápení podařilo a opravdu to funguje. IDEA má přímo tool v Code -> Convert Java File to Kotlin File, který přechod z Javy na Kotlin velmi ulehčí, ačkoliv ne vždy je 100% a je po něm z pravidla potřeba udělat ještě manuální refaktoring.

Prvním problémem, na který jsem narazil, byla skutečnost, že všechny třídy a metody v Kotlinu jsou final, z čímž si Spring – především v konfigurační třídě – nedokázal poradit, a tak jsem je musel explicitně “otevřít” pomocí klíčového slova open:

@Configuration
open class Config {

    @Bean
    open fun myBean(): MyBean {
        return MyBean()
    }
}

Když se na to teď dívám, dochází mi, že takto jednoduchá metoda by se dala refaktorovat ještě lépe:

    @Bean
    open fun myBean() = MyBean()

Dalším problémem byla anotace @Autowired, kde jsem musel Kotlin přesvědčit, že daná proměnná null obsahovat nebude, a to pomocí lateinit:

@Controller
class MainController {

    @Autowired
    lateinit private var repo: SomeRepository

Posléze jsem se dočetl a vyzkoušel, že Spring zvládne dependency nainjectovat i do konstruktoru daného kontroleru, takže nutnost použití @Autowired odpadá úplně (wow!):

@Controller
class MainController(
        val repo: SomeRepository
) {
.
.
.
}

Fajn featurou bylo, že jsem pro svůj databázový bean mohl použít data class, která mi automaticky vygenerovala gettery/settery (a další) za mě:

@Table(name = "some_table")
@Entity
data class MyBean(
    @Id
    var id: String? = null,
    var someText: String? = null,
    var show: Boolean = true,
    var someAttr: Boolean? = null
)

Možná by mohlo být fajn, kdyby se tam null doplnil automaticky, pokud žádnou hodnotu nespecifikuji (obzvláště pokud typ označím otazníkem, čímž typovému systému říkám, že může být null), ale i tak – za mě OK 🙂 .

Jako hezký příklad, jak může null check pomocí otazníku refaktorovat metodu bez nutnosti použití if statementu, bych zvolil tento:

    private fun parseSomeText(source: String): String? {
        val elem: Element? = Jsoup.parse(source)
                .select("some.selector")
                .first()

        return elem?.text()
    }

Zde by to opět šlo ještě trochu zestručnit a zapsat to jen jako jediný chain, ale z hlediska čitelnosti si myslím, že onen mezikrok uložení elementu do val elem je zde na místě.

Finálním a asi největším tweakem byla hlavní spouštěcí třída Spring Bootu, která jednak požadovala třídu (takže jsem nemohl použít pouze object) a dále statickou main metodu. Z celého vyplynulo, že jsem Javovského ekvivalentu docílil pomoci tzv. companion object a @JvmStatic anotace. Dále jsem si všiml, že Javovské Class objekty se v Kotlinu vytahují poněkud zvláštním způsobem pomocí ::class.java, ale to naštěstí IDEA vygenerovala za mě 🙂 . Z toho plyne, že používat některé Javovské knihovny v Kotlinu, které jsou na tomto založené, může být trochu nepříjemné.

@SpringBootApplication
open class MyApp {

    companion object {
        @JvmStatic fun main(args: Array<String>) {
            SpringApplication.run(MyApp::class.java, *args)
        }
    }
}

Závěr

Kotlin je docela fajn a mám v plánu ho vyzkoušet na svých budoucích soukromých projektech, ale myslím si, že pro enterprise svět by mohl být zralý až tak za 2-3 roky, nicméně našlápnuto má dle mého názoru dosti dobře. Je třeba ještě vychytat hodně much jak v jazyku samotném, tak v pluginu pro IDEU, kde občas nefunguje autocompletion atd. a pak by možná mohla přijít doba, kdy by dynamicky typované jazyky, jako např. Python, pro praktický programátorský svět již zcela ztratily smysl 🙂 .

EDIT: Zjistil jsem, že používám rok starou IDEA. Po updatu na verzi 2017 už se autocompletion jeví jako mnohem lepší.