Автор статьи: Сергей Прощаев (@sproshchaev)
Руководитель направления Java-разработки в FinTech и преподаватель курса
Kotlin Backend Developer. Professional в Otus


Всем привет, меня зовут Сергей Прощаев, и в этой статье я расскажу про то, с чего на самом деле стоит начинать большинство backend-проектов в 2026 году. Spoiler alert: это не микросервисы.

Руковожу направлением Java-разработки в FinTech и уже несколько лет преподаю курс по архитектуре в OTUS. За это время я увидел десятки проектов — от стартапов до корпоративных систем. И всё чаще наблюдаю одну и ту же картину: команда из пяти человек с горящими глазами начинает новый продукт и сразу погружается в docker-compose с пятью сервисами, Kafka для событий и service mesh «на будущее». Через три месяца они тонут в complexity, а бизнес требует первую версию. Знакомо?

Сегодня мы пойдём другим путём. Я покажу, как собрать простое, но полноценное монолитное приложение на Spring Boot и Kotlin — тот самый надежный фундамент, который позволит вам запустить MVP за недели, а не месяцы. А в конце расскажу, где можно системно прокачать навыки Kotlin-разработчика, чтобы строить такие системы уже профессионально.


Слон в посудной лавке, или почему все говорят про микросервисы, а вы пока должны выбрать монолит?

Когда в 2016 году Netflix рассказывал на конференциях про свой микросервисный зоопарк, казалось, что будущее за распределёнными системами. Многие, включая меня в начале карьеры, попали в эту ловушку. Мы начинали проект с мыслью: «сделаем как у Netflix» — и тут же начинали пилить сервисы.

Но реальность куда прозаичнее. В 2024-2025 годах на Хабре шли жаркие споры, и тренд начал меняться. Опытные разработчики массово делились историями, как они «вернулись к монолиту» или отложили распил на годы. Цифры говорят сами за себя: для команды до 15 человек накладные расходы на orchestration, межсервисное взаимодействие, трассировку и обеспечение консистентности данных могут увеличить сложность системы на 50-100%, не принося при этом бизнесу ровным счётом никакой пользы на старте.

В одном из fintech-стартапов, в соответствии с техническим заданием заказчика, мы потратили 4 месяца на запуск «идеальной» микросервисной архитектуры. А конкурент за те же 4 месяца на монолите (тоже Spring Boot + Kotlin) выпустил три крупных обновления и первым вышел на рынок. Их CTO потом признался: «Монолит давал нам скорость разработки в 2-3 раза выше. Мы просто успевали больше».

Вывод прост: монолит — не «устаревшая архитектура», а стратегический инструмент. Он позволяет:

  • Запустить работающий прототип за дни, а не недели.

  • Иметь один деплой, одну базу данных, один лог — и в 3 раза меньше головной боли при отладке.

  • Масштабироваться вертикально до десятков тысяч RPS (а этого хватит 95% проектов на первых 3-5 годах жизни).

И когда вы достигаете реальных границ монолита (например, 50+ разработчиков в команде или необходимость независимо масштабировать конкретные компоненты в 100 раз), вы уже имеете работающий продукт, понимание домена и ресурсы для осмысленного перехода к распределённой архитектуре.

Kotlin + Spring Boot: Любовь с первого data class

Почему именно эта связка? Когда я впервые попробовал писать Spring-приложение на Kotlin в 2018 году, это было похоже на прозрение. Всё то, что в Java занимало десятки строк шаблонного кода (геттеры, сеттеры, equals, hashCode, Builder), в Kotlin ужималось в одну строку data class.

Но дело не только в синтаксическом сахаре. Kotlin привносит в экосистему Spring философию безопасности и выразительности.

  • Null Safety: Компилятор не даст вам сделать NullPointerException — главного врага джавистов. Spring прекрасно с этим работает.

  • Корутины: Асинхронный код без hell'а колбэков. Spring WebFlux и корутины — это мощность реактивных систем с почти синтаксисом блокирующего кода.

  • Extension-функции: Вы можете «добавлять» методы к любым классам, включая классы Spring. Хотите, чтобы String валидировался как email? "user@mail.com".isValidEmail() — и вот вы уже написали утилиту, которая читается как родной метод.

Всё это не просто «удобно». Это меняет подход к разработке: меньше ошибок на этапе компиляции, больше сосредоточенности на бизнес-логике. И Spring Boot, как самый популярный фреймворк в мире Java, полностью адаптировался под Kotlin, предлагая идиоматичную поддержку.

Наш стек для сегодняшнего примера:

  • Kotlin 1.9+

  • Spring Boot 3.2+ (с нативной поддержкой Kotlin coroutines)

  • Spring Data JPA (для работы с БД)

  • H2 Database (in-memory для простоты, в продакшене — PostgreSQL)

  • Gradle Kotlin DSL (конфигурация как код, тоже на Kotlin!)

Практика: Собираем User Service за 15 минут

Давайте создадим простое приложение — сервис управления пользователями (User Service). Это будет классический CRUD (Create, Read, Update, Delete) с REST API. Я покажу структуру и ключевые моменты.

1. Структура проекта (Modular Monolith)

Сразу приучим себя к хорошему тону — даже в монолите делаем модульную структуру. Это задел на будущее.

2. Домен: Сущность User

Вот где сияет Kotlin. Вся сущность в 15 строках вместо 50 на Java.

// user/domain/User.kt
package com.example.userapp.user.domain

import jakarta.persistence.*
import java.time.LocalDateTime

@Entity
@Table(name = "users")
data class User(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long? = null, // ID может быть null до сохранения в БД

    @Column(nullable = false, unique = true)
    val email: String,

    @Column(nullable = false)
    var name: String, // var, потому что имя можно изменить

    @Column(nullable = false)
    val createdAt: LocalDateTime = LocalDateTime.now()
)

В этом фрагменте: 

  • data class: Автоматически дает equals(), hashCode(), toString(), copy().

  • Дефолтные значения: id = null, createdAt = LocalDateTime.now() — это удобно и безопасно.

  • Аннотации JPA (@Entity, @Table): Работают точно так же, как в Java. Spring Data JPA их прекрасно понимает.

3. Слой данных: Репозиторий

С Spring Data JPA создание репозитория — это магия в одну строчку.

// user/infrastructure/UserRepository.kt
package com.example.userapp.user.infrastructure

import com.example.userapp.user.domain.User
import org.springframework.data.jpa.repository.JpaRepository

interface UserRepository : JpaRepository<User, Long> {
    fun findByEmail(email: String): User?
}

Мы объявили интерфейс, а Spring сам сгенерирует реализацию со всеми методами CRUD (save, findById, deleteById и т.д.). Метод findByEmail также будет реализован автоматически благодаря convention over configuration. Это называется Derived Query.

4. Бизнес-логика: Сервис

Сервис — это место, где живут правила. Давайте напишем его с использованием возможностей Kotlin.

// user/application/UserService.kt
package com.example.userapp.user.application

import com.example.userapp.user.domain.User
import com.example.userapp.user.infrastructure.UserRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class UserService(private val userRepository: UserRepository) {

    fun getAllUsers(): List<User> = userRepository.findAll()

    fun getUserById(id: Long): User? = userRepository.findById(id).orElse(null)

    @Transactional
    fun createUser(email: String, name: String): User {
        // Пример бизнес-правила: email должен быть уникальным
        if (userRepository.findByEmail(email) != null) {
            throw IllegalArgumentException("User with email $email already exists")
        }
        return userRepository.save(User(email = email, name = name))
    }

    @Transactional
    fun updateUserName(id: Long, newName: String): User? {
        return userRepository.findById(id)
            .map { user ->
                user.name = newName // Меняем var-поле name
                userRepository.save(user)
            }
            .orElse(null)
    }

    @Transactional
    fun deleteUser(id: Long) {
        userRepository.deleteById(id)
    }
}

На что здесь обратить внимание:

  • @Transactional: Spring управляет транзакциями. Если в методе что-то пойдёт не так, все изменения в БД откатятся.

  • Конструктор с private val: Автоматическое внедрение зависимости (Dependency Injection) через первичный конструктор — идиоматичный способ для Kotlin.

  • map и orElse: Работа с Optional из Java в стиле Kotlin.

5. Представление: REST Controller

Контроллер — это точка входа для нашего API.

// user/infrastructure/UserController.kt
package com.example.userapp.user.infrastructure

import com.example.userapp.user.application.UserService
import com.example.userapp.user.domain.User
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/api/users")
class UserController(private val userService: UserService) {

    @GetMapping
    fun getAllUsers(): List<User> = userService.getAllUsers()

    @GetMapping("/{id}")
    fun getUserById(@PathVariable id: Long): User? = userService.getUserById(id)

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    fun createUser(@RequestParam email: String, @RequestParam name: String): User {
        return userService.createUser(email, name)
    }

    @PatchMapping("/{id}")
    fun updateUserName(@PathVariable id: Long, @RequestParam name: String): User? {
        return userService.updateUserName(id, name)
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    fun deleteUser(@PathVariable id: Long) {
        userService.deleteUser(id)
    }
}

6. Запуск

Главный класс приложения стандартный:

// UserAppApplication.kt
package com.example.userapp

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class UserAppApplication

fun main(args: Array<String>) {
    runApplication<UserAppApplication>(*args)
}

Запустите приложение, и оно будет доступно на http://localhost:8080. Вот и всё! У вас есть работающий backend с API. Вы можете тестировать его через curl, Postman или Swagger UI (если добавите springdoc-openapi-starter-webmvc-ui).

Что дальше? Штрихи, которые делают приложение production-ready

Наш базовый CRUD работает. Но в реальном проекте этого недостаточно. Вот куда обычно движется разработка, и как Kotlin помогает на каждом шагу:

  • Валидация. Аннотации @NotBlank, @Email из jakarta.validation прекрасно работают с Kotlin. Добавьте @Valid в параметры контроллера.

  • Обработка ошибок. Создайте @ControllerAdvice класс. Используйте sealed class (продвинутая фича Kotlin) для моделирования разнотипных ошибок API.

  • Безопасность. Подключите Spring Security. Kotlin DSL для конфигурации Security (http { ... }) читается как история на чистом английском.

  • Логирование. Используйте log property, которую предоставляет Kotlin, или экстеншены вроде log.info { "Создан пользователь: $email" } (с ленивым вычислением строки).

Мой ход мысли на этом этапе обычно такой: сначала я делаю самый простой работающий вариант, как выше. Затем добавляю валидацию, потому что увидел в логах ConstraintViolationException. Потом — глобальный обработчик ошибок, чтобы клиент получал красивые JSON-ошибки, а не стектрейсы. И так, итеративно, feature за feature.

Заключение: монолит как старт, Kotlin как суперсила

Мы с вами собрали полноценный backend-сервис на Spring Boot и Kotlin буквально за полчаса. Это и есть сила монолита: скорость, простота, концентрация на бизнес-ценности. Вы не тратите время на настройку десятка вспомогательных сервисов. Вы пишете код, который решает задачи пользователя.

Kotlin в этой связке — не просто «более лаконичная Java». Это язык, который заставляет думать о null-безопасности, поощряет иммутабельность и предоставляет инструменты (data class, sealed class, extensions, корутины) для написания более надёжного и выразительного кода с меньшими усилиями.

Но это только начало пути. В реальном проекте вам быстро понадобятся:

  • Работа с несколькими источниками данных (БД, кеш, очереди).

  • Сложная бизнес-логика с транзакциями.

  • Асинхронная обработка через корутины или Kafka.

  • Написание интеграционных и модульных тестов.

  • Оптимизация производительности и работы с памятью в JVM.

Всему этому можно научиться методом проб и ошибок, растянув процесс на годы. А можно — системно и под руководством практикующих экспертов.

На курсе "Kotlin Backend Developer. Professional" мы не просто повторяем документацию. Мы разбираем:

  • Как проектировать отказоустойчивые и масштабируемые приложения с самого начала (даже монолиты).

  • Глубокую работу с Spring Framework 6+ и Spring Boot 3+ в контексте Kotlin.

  • Построение архитектуры: когда и как правильно «распиливать» монолит, как работать с событиями и сообщениями.

  • Все инструменты современного бэкенд-разработчика: Docker, Kubernetes, мониторинг, профилирование.

Этот курс — для тех, кто хочет не просто писать код, а строить системы. Системы, которые будут служить годами, масштабироваться под нагрузку и становиться основой бизнеса.

Если вас заинтересовал подход Kotlin + Spring Boot и вы хотите изучить все тонкости профессиональной backend-разработки, приглашаю на открытый урок «Разработка монолитного приложения со Spring», который пройдет 4 февраля в 19:00 в рамках курса. Участие бесплатное, нужна регистрация.