Kotlin Academy · Lekcja

Funkcjonalne modelowanie domeny za pomocą typów podstawowych Arrow

Modeluj złożone domeny za pomocą Either, NonEmptyList oraz akumulowania zweryfikowanych błędów.

Lekcja 4 z 413 kroki

Funkcjonalne modelowanie domeny za pomocą typów podstawowych Arrow to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Czym jest funkcyjne modelowanie domeny?

Funkcyjne modelowanie domeny wykorzystuje typy algebraiczne (Either, Option, klasy sealed) do zapisywania reguł biznesowych w typach. Nieprawidłowe stany stają się niemożliwe do utworzenia już na etapie kompilacji, a błędy są jawnie określone w sygnaturach funkcji — bez ukrytych wyjątków.

Obiekty wartości za pomocą klas inline/value

Używaj klas wartości Kotlinu do opakowywania typów prostych i zapobiegania obsesji na punkcie typów prostych. System typów odrzuci przekazanie UserId w miejscu, w którym oczekiwany jest PostId:

@JvmInline value class UserId(val value: Long)
@JvmInline value class PostId(val value: Long)

fun findUser(id: UserId): Either<UserError, User> = TODO()
// findUser(PostId(1L))  // Compile error!

Klasy sealed dla błędów domenowych

Modeluj błędy jako hierarchie klas sealed. Każda podklasa zawiera tylko dane istotne dla danego przypadku błędu:

sealed class UserError {
    data class NotFound(val id: UserId) : UserError()
    data class EmailTaken(val email: String) : UserError()
    data class ValidationFailed(val field: String, val reason: String) : UserError()
}

Validated: agregowanie wielu błędów

Jeśli chcesz zgłosić wszystkie błędy walidacji naraz, a nie tylko pierwszy, użyj Validated z Arrow (lub zipOrAccumulate w Raise DSL). Błędy zostaną zagregowane w NonEmptyList:

import arrow.core.Validated
import arrow.core.valid
import arrow.core.invalid

fun validateName(name: String): Validated<String, String> =
    if (name.isNotBlank()) name.valid() else "Name is blank".invalid()

Łączenie walidacji

Używaj zip(), aby łączyć wiele wyników typu Validated. Jeśli którykolwiek z nich ma status Invalid, wszystkie błędy zostaną zagregowane:

val result: Validated<NonEmptyList<String>, User> =
    validateName(name).zip(validateEmail(email)) { n, e -> User(n, e) }
        .mapLeft { it }

Uniemożliwianie reprezentowania nieprawidłowych stanów

Zamiast klasy User z nullable email i flagą isVerified użyj podklas sealed, aby system typów uniemożliwił dostęp do adresu e-mail niezweryfikowanego użytkownika:

sealed class User {
    data class Unverified(val id: UserId, val pendingEmail: String) : User()
    data class Verified(val id: UserId, val email: String) : User()
}

Inteligentne konstruktory

Używaj fabrycznych funkcji obiektu companion, które zwracają Either lub Option, zamiast publicznych konstruktorów. Dzięki temu instancje zawsze będą znajdować się w prawidłowym stanie:

class Email private constructor(val value: String) {
    companion object {
        fun of(raw: String): Either<String, Email> =
            if (raw.contains("@") && raw.length <= 255) Email(raw).right()
            else "Invalid email format".left()
    }
}

Łączenie Either i Option w potoku operacji

Rzeczywista operacja domenowa zazwyczaj łączy wyszukiwanie w repozytoriach (Option) z walidacją (Either). Użyj bloku either { } biblioteki Arrow wraz z .bind(), aby płynnie je komponować:

fun createPost(authorId: UserId, title: String, body: String): Either<PostError, Post> = either {
    val author = userRepo.findById(authorId).toEither { PostError.AuthorNotFound }.bind()
    val validTitle = validateTitle(title).bind()
    postRepo.save(Post(author, validTitle, body))
}

Niezmienność i copy

Encje domenowe powinny być niezmienne. Używaj klas danych i copy(), aby wyprowadzać nowe stany. Lens biblioteki Arrow (z arrow-optics) umożliwia wygodne zagnieżdżone aktualizacje bez mutowania danych:

val updated = user.copy(email = "new@example.com")
// Arrow Optics:
val emailLens = User.email
val updatedWithLens = emailLens.set(user, "new@example.com")

Konfiguracja bezpieczna pod względem typów za pomocą klas sealed

Modeluj warianty konfiguracji aplikacji za pomocą klas sealed, aby kompilator wymuszał obsługę każdego przypadku:

sealed class DbConfig {
    data class Postgres(val url: String, val user: String, val pass: String) : DbConfig()
    data class InMemory(val dbName: String = "test") : DbConfig()
}

Korzyści w skrócie

Funkcyjne modelowanie domeny z użyciem podstawowych typów Arrow zapewnia:

  • Brak wyjątków null pointer w kodzie domenowym
  • Błędy widoczne w sygnaturach funkcji
  • Kompletne sprawdzanie hierarchii sealed za pomocą when
  • Funkcje czyste, które można łatwo testować
  • Kod, który sam dokumentuje swoje działanie

Szybkie sprawdzenie

Jaka jest główna korzyść z używania hierarchii sealed class dla błędów domenowych zamiast zgłaszania wyjątków?

Podsumowanie: funkcyjne modelowanie domeny za pomocą podstawowych typów Arrow

Najważniejsze informacje:

  • Klasy wartości zapobiegają obsesji na punkcie typów prostych
  • Hierarchie błędów sealed zapewniają kompletną i bezpieczną typowo obsługę przypadków niepowodzenia
  • Inteligentne konstruktory gwarantują prawidłowe instancje
  • either { }.bind() przejrzyście łączy operacje, które mogą zakończyć się niepowodzeniem
  • Niezmienne dane + copy() / Arrow Optics zapewniają bezpieczne przejścia między stanami
Bezpłatny start

Ucz się Kotlin dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
51
Lekcje
203

Często zadawane pytania

Czy lekcja „Funkcjonalne modelowanie domeny za pomocą typów podstawowych Arrow” jest bezpłatna?

Tak — pełny tekst „Funkcjonalne modelowanie domeny za pomocą typów podstawowych Arrow” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Funkcjonalne modelowanie domeny za pomocą typów podstawowych Arrow”?

Modeluj złożone domeny za pomocą Either, NonEmptyList oraz akumulowania zweryfikowanych błędów. Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?

Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Funkcjonalne modelowanie domeny za pomocą typów podstawowych Arrow”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?

Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Either : typowana obsługa błędów bez wyjątków
  2. DSL Raise w Arrow: składanie typowanych błędów
  3. Option i nullable: kiedy używać każdego z nich
  4. Funkcjonalne modelowanie domeny za pomocą typów podstawowych Arrow
← Powrót do Kotlin Academy