Kotlin

Два года в продакшне и ни единого разрыва

Паша Финкельштейн

Не для тех, кто уже

Дазы Банных

Spring + Kotlin. Part 1. @Transactional

@Transactional
class MySmartService(repo1: Repository1, repo2: Repository2) {
    fun complex(datum: String): Result {
        val interim = repo1.save(datum)
        return repo2.destroy(someOp(interim))
    }
    fun someOp(input: String) =
        if (notLucky(input)) throw Exception("Sorry, bro") else input

Spring + Kotlin. Part 1. @Transactional

@Transactional
class MySmartService(repo1: Repository1, repo2: Repository2) {
    fun complex(datum: String): Result {
        val interim = repo1.save(datum)
        return repo2.destroy(someOp(interim))
    }
    fun someOp(input: String) =
        if (notLucky(input)) throw Exception("Sorry, bro") else input

Spring + Kotlin. Part 1. @Transactional

@Transactional
class MySmartService(repo1: Repository1, repo2: Repository2) {
    fun complex(datum: String): Result {
        val interim = repo1.save(datum)
        return repo2.destroy(someOp(interim))
    }
    fun someOp(input: String) =
        if (notLucky(input)) throw Exception("Sorry, bro") else input

Spring + Kotlin. Part 1. @Transactional

@Transactional
class MySmartService(repo1: Repository1, repo2: Repository2) {
    fun complex(datum: String): Result {
        val interim = repo1.save(datum)
        return repo2.destroy(someOp(interim))
    }
    fun someOp(input: String) =
        if (notLucky(input)) throw Exception("Sorry, bro") else input

Что может пойти не так?

Spring + Kotlin. Part 1. @Transactional

@Transactional
class MySmartService(repo1: Repository1, repo2: Repository2) {
    fun complex(datum: String): Result {
        val interim = repo1.save(datum)
        return repo2.destroy(someOp(interim))
    }
    fun someOp(input: String) =
        if (notLucky(input)) throw Exception("Sorry, bro") else input

Spring + Kotlin. Part 1. @Transactional

@Transactional
open class MySmartService(repo1: Repository1, repo2: Repository2) {
    open fun complex(datum: String): Result {
        val interim = repo1.save(datum)
        return repo2.destroy(someOp(interim))
    }
    fun someOp(input: String) =
        if (notLucky(input)) throw Exception("Sorry, bro") else input

Spring + Kotlin. Part 1. @Transactional

@Transactional
class MySmartService(repo1: Repository1, repo2: Repository2) {
    fun complex(datum: String): Result {
        val interim = repo1.save(datum)
        return repo2.destroy(someOp(interim))
    }
    fun someOp(input: String) =
        if (notLucky(input)) throw Exception("Sorry, bro") else input

Spring + Kotlin. Part 1. @Transactional

Проблемы

  • Всё final
  • Прокси не создаются
  • Конфигурации не работают

Решения

  • kotlin-allopen + kotlin-spring
    • The code is a lie ⇒ сложное кодревью
    • Конструкция хрупкая
  • Всюду явно писать open
    • boilerplate

Spring + Kotlin. Part 2. @Transactional

@Transactional
open class MySmartService(repo1: Repository1, repo2: Repository2) {
    open fun complex(datum: String): Result {
        val interim = repo1.save(datum)
        return repo2.destroy(someOp(interim))
    }
    fun someOp(input: String) =
        if (notLucky(input)) throw Exception("Sorry, bro") else input
Что может пойти не так?

Collateral damage

Spring + Kotlin. Part 2. @Transactional

@Transactional
open class MySmartService(repo1: Repository1, repo2: Repository2) {
    open fun complex(datum: String): Result {
        val interim = repo1.save(datum)
        return repo2.destroy(someOp(interim))
    }
    fun someOp(input: String) =
        if (notLucky(input)) throw Exception("Sorry, bro") else input

Исключения

Как они устроены?

Исключения

public static RuntimeException sneakyThrow(Throwable t) {
    if (t == null) throw new NullPointerException("t");
    return Lombok.<RuntimeException>sneakyThrow0(t);
}

@SuppressWarnings("unchecked")
private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
    throw (T)t;
}
                        

Исключения

public static RuntimeException sneakyThrow(Throwable t) {
    if (t == null) throw new NullPointerException("t");
    return Lombok.<RuntimeException>sneakyThrow0(t);
}

@SuppressWarnings("unchecked")
private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
    throw (T)t;
}
                        

Транзакция не откатится!

Spring + Kotlin. Part 2. @Transactional

Проблема

Не откатываются транзакции

Решение

Внимательно следить за сторонними исключениями

Не создавать свои checked

Баллада об inline

@Transactional
open class SomeService(val repo: SomeRepo){
    open fun someFunc(mapper: (DTO)->Long): List<Long> =
        repo
            .someAction()
            .map{ mapper(it) }

Баллада об inline

@Transactional
open class SomeService(val repo: SomeRepo){
    open fun someFunc(mapper: (DTO)->Long): List<Long> =
        repo
            .someAction()
            .map{ mapper(it) }

Баллада об inline

@Transactional
open class SomeService(val repo: SomeRepo){
    open fun someFunc(mapper: (DTO)->Long): List<Long> =
        repo
            .someAction()
            .map{ mapper(it) }

Баллада об inline

@Transactional
open class SomeService(val repo: SomeRepo){
    open fun someFunc(mapper: (DTO)->Long): List<Long> =
        repo
            .someAction()
            .map{ mapper(it) }

Но есть же inline

Улучшаем!

Баллада об inline

@Transactional
open class SomeService(val repo: SomeRepo){
    inline open fun someFunc(mapper: (DTO)->Long): List<Long> =
        repo
            .someAction()
            .map{ mapper(it) }

 

 

Баллада об inline

Проблема

  • inline инлайнится даже когда не надо

Решение

  • Все зависимости надо делать приватными
  • Думать когда пользуешься inline

Мы ынтырпрайз, у нас JPA, а не ваши хипстерские штучки

kotlin-maven-plugin
org.jetbrains.kotlin

    
        jpa
    


    
        org.jetbrains.kotlin
        kotlin-maven-noarg
    

                    

Мы ынтырпрайз, у нас JPA, а не ваши хипстерские штучки

kotlin-maven-plugin
org.jetbrains.kotlin

    
        jpa
    


    
        org.jetbrains.kotlin
        kotlin-maven-noarg
    

                

Мы ынтырпрайз, у нас JPA, а не ваши хипстерские штучки

kotlin-maven-plugin
org.jetbrains.kotlin

    
        jpa
    


    
        org.jetbrains.kotlin
        kotlin-maven-noarg
    

                        

Мы ынтырпрайз, у нас JPA, а не ваши хипстерские штучки

kotlin-maven-plugin
org.jetbrains.kotlin

    
        jpa
    


    
        org.jetbrains.kotlin
        kotlin-maven-noarg