Автосчетчик номера сборки (autoincrement build version)

Стоит важная задача государственной важности — нарисовать формочку «О программе» smile где водится всякая инфа о версиях компонент. И оказалось, что у нас нет версии билда. Это не проблема, ведь есть готовое решение. Как раз у спрингбута есть готовый класс, который предоставляет версию. Но не тут-то было.

Версию он не возвращает от слова совсем.

Начинаем опять воевать с грэдлом.

Сначала создаем файлик version.properties и кладем его в корень проекта. Затем делаем таску в корневом gradle.build для автоинкримента при каждом билде.

task('increaseBuildVersion')  {
   def versionPropsFile = project.rootProject.file('version.properties')
   if (versionPropsFile.canRead()) {
       def versionProps = new Properties()
       versionProps.load(new FileInputStream(versionPropsFile))

       def code = versionProps['build_version'].toInteger()+1

       versionProps['build_version'] = code.toString()
       versionProps.store(versionPropsFile.newWriter(), null)
   } else {
       throw new GradleException("Could not read version.properties!")
   }
}.dependsOn('build')

Затем (если gradle.build несколько, то в тот, который в спрингбутовом контексте лежит) дописываем скриптик, чтобы его (спрингбута) класс увидел наши проперти:

ext{
   def versionPropsFile = project.rootProject.file('version.properties')
   def versionProps = new Properties()
   versionProps.load(new FileInputStream(versionPropsFile))
   build_version=versionProps['build_version']
}
springBoot{
   buildInfo {
       properties {
           additional = [
                   'product_name': "$product_name",
                   'product_version': "$product_version",
                   'build_version': "$project.ext.build_version",
                   'java_version': "$java_version"
           ]
       }
   }
}

Ну а далее пишем сервис, который все это добро будет выдавать:

@Service
class AboutInfoService(
    private val buildProperties: BuildProperties?) {

    fun getAboutInfo() = AboutInfo.create {
        it[productName] = buildProperties?.get("product_name")
        it[productVersion] = buildProperties?.get("product_version")
        it[buildNumber] = buildProperties?.get("build_version")
        it[javaVersion] = buildProperties?.get("java_version")
    }
}

Все замечательно работает, версия инкрементиццо, все казалось бы хорошо, но пришла беда откуда не ждали…

Что, блять, делать, если несколько разработчиков одновременно начнут коммитить свою version.properties?!

Маленькое дерево с большой проблемой

Прошло 2 месяца — в Котлине освоился, но React еще доводит до кипения.
На днях случилось: воевал я с новым компонентом от Ant.design — TreeSelect, ну чтобы выбирать значение в дереве. Нарисовал быстро, а как данные загрузить до прорисовки понял не сразу. Выход нашелся, когда уже глаза покраснели — рисовать спин, а загружать в componentDidMount. Все это успешно отладилось на песочнице, но когда доехало в прод, начались дииикие тормоза. А все из-за того, что записей в дереве получилось в 10 раз больше. А как дерево строится? Ну как обычно рекурсией, а это самая медленная из операций — цикл в цикле, а еще вся эта радость крутиться не на сервере, а на клиенте. Поэтому скорость упала не в 10 раз, а в 100.
Короче, я попал на самую распространенную задачу при отображении дерева с большим количеством элементов. Обычная практика — выделился узел, дети подтянулись. Но этот TreeSelect этот принимает на вход только целое дерево и не умеет подгружать узлы по запросу.

В итоге пришлось отказаться от этого компонента, и использовать другой (коллеги подсказали, что есть готовый), который это умеет.
(Вот и всё)х2 )))

Коктейль из Java, Kotlin и ReactJS

Итак, я сменил галеру место работы. И, неожиданно, технологии. Java есть, номинально, но на текущий момент, плотно уже 3 недели изучаю Kotlin в связке с ReactJS.

До этого я конечно слышал, про них, но не пробовал. По котлину пару обучающих видео посмотрел и вперед.

Первые впечатления: точка-с-запятой не нужна, типы указываем после переменной, тернарный оператор урезан и стал «элвис» оператором, статических полей нет, финальная и нефинальная переменные обозначаются val и var, функции заменили методы, все классы по-умолчанию финальные. Аааааа-ааа-а!!!

Пример:

fun getPrintTemplate(data: Map<String, Any?>, metadata: MutableList<String> = mutableListOf()): MutableList<String> {
 data.forEach { entry ->
            val value = entry.value
            if (value is Collection<*> && value.isNotEmpty()) {
                (value.first() as Map<String, Any?>)
                        .keys
                        .forEach { subKey -> metadata.add("${entry.key}.$subKey") }
            }
            if (value is Map<*, *>) getPrintTemplate(value as Map<String, Any?>, metadata)
}
    return metadata
}

По реакту — это даже не фреймворк, напрямую не пишем? а под котлин это выглядит как работа с обычными классами.
Вот например создаем элемент:

fun RBuilder.downloadLink(fileName: String, dataFunc: suspend () -> String, body: ((RBuilder).() -> Unit)? = null) {
    a {
        attrs.onClickFunction = {
            async {
                val base64data = dataFunc()
                downloadFile(base64data, fileName).invoke()
            }
        }
        if (body != null) {
            body()
        } else {
            +fileName
            +" "
            icon("download")
        }
    }
}

А потом обращаемся к нему:

    row{
        downloadLink(attach[Attachment.displayName], dataFunc = { handleDownload() })
    }

 

В общем как новый язык изучать. Угораздило жеж ))