Kotlin: Desenvolvimento de Projetos Kotlin Explicado

Última atualização: 2026-08-26

O design está pronto — agora é hora de codar. Charlie, Alice e Bob colaboram para implementar o código de quatro camadas do OrderProcessor: camada de domínio (Order + eventos), camada de serviço (lógica de negócio + corrotinas), camada de persistência (Repository) e camada de integração (clientes HTTP).

1. O que Você Aprenderá


2. A História Real de uma Equipe

(1) Problema: Divisão de Trabalho Incerta Causa Conflitos

Alice e Bob modificaram OrderService simultaneamente — 10 conflitos Git. Causa raiz: sem divisão de trabalho por camada, ambos editavam o mesmo arquivo.

(2) Solução de Divisão por Camada

TEXT 📖 Somente leitura
Charlie: Camada de domínio (Order, OrderEvent, StateMachine)
Alice:   Camada de serviço (OrderService, lógica de negócio)
Bob:     Repository + Camada de integração (acesso a dados, clientes HTTP)

Arquitetura em camadas = divisão de trabalho em camadas. Cada camada se desenvolve independentemente, com contratos de interface minimizando conflitos.


3. Camada de Domínio

(1) Entidades Centrais

KOTLIN
// Entidades de domínio - Kotlin puro, sem dependência de framework
data class OrderItem(
    val sku: String,
    val quantity: Int,
    val unitPrice: Double
) {
    val subtotal: Double get() = quantity * unitPrice
    init {
        require(quantity > 0) { "Quantity must be positive" }
        require(unitPrice >= 0) { "Price must be non-negative" }
    }
}

data class Address(
    val street: String,
    val city: String,
    val country: String
)

data class Order(
    val id: String,
    val customerId: String,
    val items: List<OrderItem>,
    val shippingAddress: Address?,
    var status: OrderStatus,
    var trackingCode: String?,
    val createdAt: String,
    var updatedAt: String?
) {
    val total: Double get() = items.sumOf { it.subtotal }

    init {
        require(id.startsWith("ORD-")) { "Invalid order ID format" }
        require(items.isNotEmpty()) { "Order must have at least one item" }
    }
}

(2) Status e Eventos

KOTLIN
sealed class OrderStatus {
    data class Pending(val createdAt: String) : OrderStatus()
    data class Confirmed(val confirmedAt: String) : OrderStatus()
    data class Shipped(val trackingCode: String, val shippedAt: String) : OrderStatus()
    data class Delivered(val deliveredAt: String) : OrderStatus()
    data class Cancelled(val reason: String, val cancelledAt: String) : OrderStatus()
}

sealed class OrderEvent {
    abstract val orderId: String
    abstract val timestamp: String

    data class Created(
        override val orderId: String,
        val customerId: String,
        val total: Double,
        override val timestamp: String
    ) : OrderEvent()

    data class Confirmed(override val orderId: String, override val timestamp: String) : OrderEvent()
    data class Shipped(override val orderId: String, val trackingCode: String, override val timestamp: String) : OrderEvent()
    data class Delivered(override val orderId: String, override val timestamp: String) : OrderEvent()
    data class Cancelled(override val orderId: String, val reason: String, override val timestamp: String) : OrderEvent()
}

(3) Máquina de Estados

KOTLIN
object OrderStateMachine {
    fun transition(current: OrderStatus, event: OrderEvent): OrderStatus = when {
        current is OrderStatus.Pending && event is OrderEvent.Confirmed ->
            OrderStatus.Confirmed(event.timestamp)
        current is OrderStatus.Confirmed && event is OrderEvent.Shipped ->
            OrderStatus.Shipped(event.trackingCode, event.timestamp)
        current is OrderStatus.Shipped && event is OrderEvent.Delivered ->
            OrderStatus.Delivered(event.timestamp)
        current is OrderStatus.Pending && event is OrderEvent.Cancelled ->
            OrderStatus.Cancelled(event.reason, event.timestamp)
        else ->
            throw IllegalStateException("Invalid transition from $current with $event")
    }

    fun canTransition(current: OrderStatus, event: OrderEvent): Boolean = when {
        current is OrderStatus.Pending && event is OrderEvent.Confirmed -> true
        current is OrderStatus.Confirmed && event is OrderEvent.Shipped -> true
        current is OrderStatus.Shipped && event is OrderEvent.Delivered -> true
        current is OrderStatus.Pending && event is OrderEvent.Cancelled -> true
        else -> false
    }
}

4. Camada de Serviço

(1) OrderService

KOTLIN
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

class OrderService(
    private val repository: OrderRepository,
    private val eventStore: EventRepository,
    private val paymentClient: PaymentClient,
    private val inventoryClient: InventoryClient
) {
    suspend fun createOrder(request: CreateOrderRequest): Order {
        val order = Order(
            id = generateOrderId(),
            customerId = request.customerId,
            items = request.items.map { OrderItem(it.sku, it.quantity, it.unitPrice) },
            shippingAddress = request.shippingAddress,
            status = OrderStatus.Pending(request.timestamp),
            trackingCode = null,
            createdAt = request.timestamp,
            updatedAt = null
        )
        repository.save(order)
        eventStore.append(OrderEvent.Created(order.id, order.customerId, order.total, request.timestamp))
        return order
    }

    suspend fun confirmOrder(orderId: String, timestamp: String): Order {
        val order = repository.findById(orderId) ?: throw NoSuchElementException("Order $orderId not found")
        val event = OrderEvent.Confirmed(orderId, timestamp)
        val newStatus = OrderStateMachine.transition(order.status, event)
        order.status = newStatus
        order.updatedAt = timestamp
        repository.save(order)
        eventStore.append(event)
        return order
    }

    suspend fun shipOrder(orderId: String, trackingCode: String, timestamp: String): Order {
        val order = repository.findById(orderId) ?: throw NoSuchElementException("Order $orderId not found")
        val event = OrderEvent.Shipped(orderId, trackingCode, timestamp)
        val newStatus = OrderStateMachine.transition(order.status, event)
        order.status = newStatus
        order.trackingCode = trackingCode
        order.updatedAt = timestamp
        repository.save(order)
        eventStore.append(event)
        return order
    }

    fun orderEvents(orderId: String): Flow<OrderEvent> = flow {
        eventStore.findByOrderId(orderId).forEach { emit(it) }
    }

    private fun generateOrderId(): String = "ORD-${System.currentTimeMillis()}"
}

(2) DTOs de Requisição/Resposta

KOTLIN
data class CreateOrderRequest(
    val customerId: String,
    val items: List<CreateItemRequest>,
    val shippingAddress: AddressRequest?,
    val timestamp: String
)

data class CreateItemRequest(val sku: String, val quantity: Int, val unitPrice: Double)
data class AddressRequest(val street: String, val city: String, val country: String)

data class OrderResponse(
    val id: String,
    val customerId: String,
    val total: Double,
    val status: String,
    val items: List<OrderItemResponse>,
    val trackingCode: String?,
    val createdAt: String,
    val updatedAt: String?
)

data class OrderItemResponse(val sku: String, val quantity: Int, val unitPrice: Double, val subtotal: Double)

fun Order.toResponse() = OrderResponse(
    id, customerId, total, status::class.simpleName ?: "Unknown",
    items.map { OrderItemResponse(it.sku, it.quantity, it.unitPrice, it.subtotal) },
    trackingCode, createdAt, updatedAt
)

5. Camada de Persistência

(1) Interfaces de Repository

KOTLIN
interface OrderRepository {
    suspend fun save(order: Order)
    suspend fun findById(id: String): Order?
    suspend fun findAll(): List<Order>
    suspend fun deleteById(id: String)
}

interface EventRepository {
    suspend fun append(event: OrderEvent)
    fun findByOrderId(orderId: String): List<OrderEvent>
}

(2) Implementação In-Memory (Fase de Desenvolvimento)

KOTLIN
class InMemoryOrderRepository : OrderRepository {
    private val storage = mutableMapOf<String, Order>()

    override suspend fun save(order: Order) { storage[order.id] = order }
    override suspend fun findById(id: String) = storage[id]
    override suspend fun findAll() = storage.values.toList()
    override suspend fun deleteById(id: String) { storage.remove(id) }
}

class InMemoryEventRepository : EventRepository {
    private val events = mutableListOf<OrderEvent>()

    override suspend fun append(event: OrderEvent) { events.add(event) }
    override fun findByOrderId(orderId: String) = events.filter { it.orderId == orderId }
}

6. Camada de Integração

(1) Interfaces de Cliente HTTP

KOTLIN
interface PaymentClient {
    suspend fun processPayment(orderId: String, amount: Double): PaymentResult
}

interface InventoryClient {
    suspend fun checkAvailability(sku: String, quantity: Int): Boolean
    suspend fun reserve(sku: String, quantity: Int): ReservationResult
}

sealed class PaymentResult {
    data class Success(val transactionId: String) : PaymentResult()
    data class Failed(val reason: String) : PaymentResult()
}

sealed class ReservationResult {
    data class Reserved(val reservationId: String) : ReservationResult()
    data class Unavailable(val reason: String) : ReservationResult()
}

// Implementações simuladas
class MockPaymentClient : PaymentClient {
    override suspend fun processPayment(orderId: String, amount: Double) =
        PaymentResult.Success("TXN-${orderId.substring(4)}")
}

class MockInventoryClient : InventoryClient {
    override suspend fun checkAvailability(sku: String, quantity: Int) = quantity < 10_000
    override suspend fun reserve(sku: String, quantity: Int) =
        ReservationResult.Reserved("RES-${sku.substring(4)}")
}

7. Comparação de Responsabilidades das Quatro Camadas

Camada Responsabilidade Direção de Dependência Classes Típicas Estratégia de Teste
Domínio Regras de negócio e entidades Sem dependências Order, OrderStatus, StateMachine Testes unitários puros
Serviço Orquestração de processos de negócio → Domínio/Persistência/Integração OrderService Testes unitários com dependências mockadas
Persistência Acesso a dados → Domínio OrderRepository, EventRepository Testes de integração (Testcontainers)
Integração Chamadas a serviços externos → Domínio PaymentClient, InventoryClient Testes de contrato + Mock

(1) Comparação de Estratégias de Implementação do Repository

Fase Implementação Prós Contras
Desenvolvimento InMemory* Zero config, rápido Sem persistência
Testes Testcontainers DB real, reprodutível Requer Docker
Produção Spring Data R2DBC Nativo para corrotinas, alta performance Config de pool de conexões necessária

(2) Tabela de Regras de Transição de Estado

Estado Atual Evento Permitido Estado Destino
Pending Confirmed Confirmed
Pending Cancelled Cancelled
Confirmed Shipped Shipped
Shipped Delivered Delivered
Outras combinações Ilegais

8. Sequência Completa de Criação de Pedido

100%
sequenceDiagram
    participant Client
    participant Controller
    participant Service
    participant Repo
    participant Events
    participant Payment
    participant Inventory

    Client->>Controller: POST /api/v1/orders
    Controller->>Service: createOrder(request)
    Service->>Inventory: checkAvailability(sku, qty)
    Inventory-->>Service: Disponível
    Service->>Repo: save(order)
    Repo-->>Service: Salvo
    Service->>Events: append(Created event)
    Service->>Payment: processPayment(orderId, total)
    Payment-->>Service: Sucesso
    Service->>Repo: save(order status=Confirmed)
    Service->>Events: append(Confirmed event)
    Service-->>Controller: Order
    Controller-->>Client: 201 Created

9. Exemplo Completo

KOTLIN
// ============================================
// OrderProcessor - Implementação End-to-End
// Funcionalidade: Ciclo de vida completo do pedido com máquina de estados
// ============================================

import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking

// --- Domínio (das seções acima) ---
data class OrderItem(val sku: String, val quantity: Int, val unitPrice: Double) {
    val subtotal: Double get() = quantity * unitPrice
}

sealed class OrderStatus {
    data class Pending(val at: String) : OrderStatus()
    data class Confirmed(val at: String) : OrderStatus()
    data class Shipped(val trackingCode: String, val at: String) : OrderStatus()
    data class Cancelled(val reason: String, val at: String) : OrderStatus()
}

sealed class OrderEvent {
    abstract val orderId: String
    data class Created(override val orderId: String, val total: Double, val at: String) : OrderEvent()
    data class Confirmed(override val orderId: String, val at: String) : OrderEvent()
    data class Shipped(override val orderId: String, val code: String, val at: String) : OrderEvent()
    data class Cancelled(override val orderId: String, val reason: String, val at: String) : OrderEvent()
}

data class Order(
    val id: String, val customerId: String, val items: List<OrderItem>,
    var status: OrderStatus, var trackingCode: String?, val createdAt: String, var updatedAt: String?
) { val total: Double get() = items.sumOf { it.subtotal } }

object StateMachine {
    fun next(current: OrderStatus, event: OrderEvent): OrderStatus = when {
        current is OrderStatus.Pending && event is OrderEvent.Confirmed -> OrderStatus.Confirmed(event.at)
        current is OrderStatus.Confirmed && event is OrderEvent.Shipped -> OrderStatus.Shipped(event.code, event.at)
        current is OrderStatus.Pending && event is OrderEvent.Cancelled -> OrderStatus.Cancelled(event.reason, event.at)
        else -> error("Invalid: $current + $event")
    }
}

// --- Repository ---
class OrderRepo {
    private val db = mutableMapOf<String, Order>()
    fun save(o: Order) { db[o.id] = o }
    fun find(id: String) = db[id]
    fun findAll() = db.values.toList()
}

class EventRepo {
    private val events = mutableListOf<OrderEvent>()
    fun append(e: OrderEvent) { events.add(e) }
    fun find(orderId: String) = events.filter { it.orderId == orderId }
}

// --- Serviço ---
class OrderService(private val orders: OrderRepo, private val events: EventRepo) {
    private var counter = 0
    fun create(customerId: String, items: List<OrderItem>, at: String): Order {
        val order = Order("ORD-${++counter}", customerId, items, OrderStatus.Pending(at), null, at, null)
        orders.save(order)
        events.append(OrderEvent.Created(order.id, order.total, at))
        return order
    }
    fun confirm(id: String, at: String): Order {
        val order = orders.find(id) ?: error("Not found: $id")
        val event = OrderEvent.Confirmed(id, at)
        order.status = StateMachine.next(order.status, event)
        order.updatedAt = at
        orders.save(order)
        events.append(event)
        return order
    }
    fun ship(id: String, code: String, at: String): Order {
        val order = orders.find(id) ?: error("Not found: $id")
        val event = OrderEvent.Shipped(id, code, at)
        order.status = StateMachine.next(order.status, event)
        order.trackingCode = code
        order.updatedAt = at
        orders.save(order)
        events.append(event)
        return order
    }
    fun cancel(id: String, reason: String, at: String): Order {
        val order = orders.find(id) ?: error("Not found: $id")
        val event = OrderEvent.Cancelled(id, reason, at)
        order.status = StateMachine.next(order.status, event)
        order.updatedAt = at
        orders.save(order)
        events.append(event)
        return order
    }
    fun history(id: String) = events.find(id)
}

// --- Demo ---
fun main() {
    val service = OrderService(OrderRepo(), EventRepo())

    println("=== Demo de Desenvolvimento do OrderProcessor ===\n")

    // Criar pedidos
    val o1 = service.create("CUST-001", listOf(OrderItem("SKU-A", 3, 9.99), OrderItem("SKU-B", 1, 149.99)), "2026-07-13T10:00:00Z")
    println("Criado: ${o1.id} | Total: \$${o1.total} USD | Status: ${o1.status}")

    val o2 = service.create("CUST-002", listOf(OrderItem("SKU-C", 2, 5_000.0)), "2026-07-13T10:01:00Z")
    println("Criado: ${o2.id} | Total: \$${o2.total} USD | Status: ${o2.status}")

    // Confirmar
    val confirmed = service.confirm(o1.id, "2026-07-13T10:05:00Z")
    println("\nConfirmado: ${confirmed.id} | Status: ${confirmed.status}")

    // Enviar
    val shipped = service.ship(o1.id, "TRK-ABC123", "2026-07-13T11:00:00Z")
    println("Enviado: ${shipped.id} | Rastreio: ${shipped.trackingCode} | Status: ${shipped.status}")

    // Cancelar
    val cancelled = service.cancel(o2.id, "Solicitação do cliente", "2026-07-13T10:10:00Z")
    println("Cancelado: ${cancelled.id} | Motivo: ${(cancelled.status as OrderStatus.Cancelled).reason}")

    // Histórico de eventos
    println("\n=== Histórico de Eventos: ${o1.id} ===")
    service.history(o1.id).forEach { println("  $it") }
}

Saída:

TEXT 📖 Somente leitura
=== Demo de Desenvolvimento do OrderProcessor ===

Criado: ORD-1 | Total: $179.96 USD | Status: Pending(at=2026-07-13T10:00:00Z)
Criado: ORD-2 | Total: $10000.0 USD | Status: Pending(at=2026-07-13T10:01:00Z)

Confirmado: ORD-1 | Status: Confirmed(at=2026-07-13T10:05:00Z)
Enviado: ORD-1 | Rastreio: TRK-ABC123 | Status: Shipped(trackingCode=TRK-ABC123, at=2026-07-13T11:00:00Z)
Cancelado: ORD-2 | Motivo: Solicitação do cliente

=== Histórico de Eventos: ORD-1 ===
  Created(orderId=ORD-1, total=179.96, at=2026-07-13T10:00:00Z)
  Confirmed(orderId=ORD-1, at=2026-07-13T10:05:00Z)
  Shipped(orderId=ORD-1, code=TRK-ABC123, at=2026-07-13T11:00:00Z)

9. Exemplos práticos rápidos

▶ Exemplo: Git workflow com feature branches

BASH
# Inicializar projeto
git init
git checkout -b main
git add .
git commit -m "feat: initial project structure"

# Feature branch
git checkout -b feature/order-creation
# ... desenvolver, commitar ...
git add .
git commit -m "feat(order): add CreateOrder use case"

# Push e abrir PR
git push origin feature/order-creation
# Abrir PR no GitHub, solicitar review
# Após aprovação, merge para main

# Manutenção: hotfix branch
git checkout main
git checkout -b hotfix/critical-bug
git commit -m "fix: race condition in order creation"

▶ Exemplo: Commits semânticos

BASH
# Formato: tipo(escopo): descrição

feat: adiciona novo endpoint de cancelamento
feat(order): suporte para pedidos recorrentes
fix: corrige cálculo de imposto para pedidos internacionais
fix(cart): evita duplicação de itens

docs: atualiza README com novos exemplos
docs(api): adiciona exemplos de uso de REST

style: reformata código conforme ktlint
refactor: extrai validação para OrderValidator class

test: adiciona testes para ConfirmOrderUseCase
test(integration): testa fluxo completo de pedido

chore: atualiza dependências do Gradle
build: configura profile dev e prod
ci: adiciona workflow para GitHub Actions
perf: cacheia lookups de OrderRepository

▶ Exemplo: Pull request template

MARKDOWN
<!-- .github/pull_request_template.md -->

## Descrição
<!-- Resumo das mudanças -->

## Motivação e Contexto
<!-- Por que essas mudanças são necessárias? -->

## Como foi testado?
<!-- Descreva testes que você executou -->

## Tipo de Mudança
- [ ] Bug fix (non-breaking)
- [ ] Nova feature (non-breaking)
- [ ] Breaking change
- [ ] Documentação

## Checklist
- [ ] Código segue estilo do projeto
- [ ] Revisei minha próprias mudanças
- [ ] Comentários adicionados onde necessário
- [ ] Documentação atualizada
- [ ] Sem novos warnings
- [ ] Testes adicionados/atualizados
- [ ] Todos os testes passam localmente

## Capturas de tela (se aplicável)

## Notas adicionais

▶ Exemplo: Code review checklist

KOTLIN
// Ao revisar PR, verificar:
// [ ] 1. Design: está alinhado com arquitetura?
// [ ] 2. Funcionalidade: comportamento correto?
// [ ] 3. Complexidade: pode ser simplificado?
// [ ] 4. Tests: cobertura adequada?
// [ ] 5. Naming: nomes expressivos?
// [ ] 6. Error handling: erros tratados adequadamente?
// [ ] 7. Performance: há bottlenecks?
// [ ] 8. Security: vetores de ataque cobertos?
// [ ] 9. Documentation: atualizado?
// [ ] 10. Style: segue convenções do projeto?

// Exemplo de feedback construtivo:
// ❌ "Este código está ruim"
// ✅ "Considere extrair esta validação para uma função separada
//     para melhorar legibilidade e testabilidade"

▶ Exemplo: CI/CD GitHub Actions

YAML
# .github/workflows/build.yml
name: Build and Test

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: 17
      - name: Build with Gradle
        run: ./gradlew build --no-daemon
      - name: Run tests
        run: ./gradlew test --no-daemon
      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          files: ./build/reports/jacoco/test/jacocoTestReport.xml

▶ Exemplo: Versionamento semântico

KOTLIN
// versionamento_semantico.kts
// Formato: MAJOR.MINOR.PATCH

// MAJOR: mudanças incompatíveis em API
// MINOR: novas features backward-compatíveis
// PATCH: bug fixes backward-compatíveis

// git tags
// git tag -a v1.0.0 -m "Primeira release estável"
// git tag -a v1.1.0 -m "Adiciona pedidos recorrentes"
// git tag -a v1.1.1 -m "Corrige cálculo de frete"
// git tag -a v2.0.0 -m "Breaking change: nova estrutura de DTOs"

// Em build.gradle.kts:
version = "1.1.0"
group = "com.example"

// Gerar changelog automático
// git log v1.0.0..v1.1.0 --oneline

▶ Exemplo: Documentação com KDoc

KOTLIN
/**
 * Processador de pedidos - gerencia o ciclo de vida.
 *
 * Use cases cobertos:
 * 1. Criação: validate -> persist -> notify
 * 2. Confirmação: lookup -> state-transition -> notify
 * 3. Cancelamento: lookup -> state-transition -> notify
 *
 * @property repository Repositório de pedidos
 * @property notifier Serviço de notificações
 */
class OrderProcessor(
    private val repository: OrderRepository,
    private val notifier: Notifier
) {
    /**
     * Confirma um pedido pendente.
     *
     * @param orderId ID do pedido
     * @return Result com pedido confirmado ou erro
     * @throws IllegalStateException se pedido não está no estado correto
     */
    suspend fun confirm(orderId: String): Result<Order> {
        val order = repository.findById(orderId)
            ?: return Result.failure(NoSuchElementException("Pedido $orderId não existe"))

        check(order.status == OrderStatus.Created) {
            "Pedido não pode ser confirmado - estado atual: ${order.status}"
        }

        val confirmed = order.copy(status = OrderStatus.Confirmed(Instant.now()))
        val saved = repository.save(confirmed)
        notifier.notify(saved)
        return Result.success(saved)
    }
}

Saída:

TEXT 📖 Somente leitura
KDoc gera documentação HTML/JavaDoc automática
em sites como javadoc.io ou Dokka

❓ Perguntas Frequentes

P: A camada de domínio deve depender de um framework? R: Não. A camada de domínio é código Kotlin puro sem dependência do Spring ou qualquer framework. Isso garante que a lógica de domínio pode ser testada e reutilizada independentemente.

P: A camada de Serviço deve retornar objetos de domínio ou DTOs? R: O Serviço retorna objetos de domínio; o Controller os converte para DTOs. Responsabilidade clara de camada: o Serviço não tem consciência do HTTP.

P: Onde a máquina de estados deve ficar? R: Na camada de domínio. A máquina de estados é lógica de negócio central e não deve depender de nenhuma camada externa. Implemente-a com sealed classes puras do Kotlin.

P: Como lidar com atualizações concorrentes de estado? R: Locking otimista no banco de dados (campo version) ou locks distribuídos. No nível de corrotinas, use Mutex para proteger estado compartilhado. Para produção, locking no banco de dados é recomendado.

P: Qual cliente HTTP a camada de integração deve usar? R: Para projetos Kotlin, Ktor Client (nativo para corrotinas) é recomendado. Em ecossistemas Java, Spring WebClient também funciona. Ambos suportam suspend.

P: Como garantir que a equipe divida o trabalho por camada? R: Regras de code review: Controllers não tocam diretamente o Repository, Services não sabem sobre HTTP, a camada de Domínio não depende de frameworks. Ferramentas como ArchUnit podem garantir isso automaticamente.


📖 Resumo


📝 Exercícios

  1. Iniciante (⭐): Implemente a data class OrderItem e a sealed class OrderStatus com validação no bloco init. Dica: require()
  2. Intermediário (⭐⭐): Implemente os métodos confirm() e ship() do OrderService usando a máquina de estados para validar transições. Dica: StateMachine.transition()
  3. Avançado (⭐⭐⭐): Implemente o OrderProcessor completo de quatro camadas: domínio (Order + Event + StateMachine), serviço (OrderService + corrotinas), persistência (InMemoryRepo), integração (MockPaymentClient). Dica: Consulte o exemplo completo da seção 9

← Anterior | Próximo →

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%