0Pricing
Kotlin Academy · 강의

타입 안전한 HTML/Config DSL 만들기

빌더 패턴과 확장 람다를 사용해 간단한 설정 DSL을 구현해 보세요.

타입 안전한 HTML/Config DSL 만들기은(는) CoddyKit의 무료 Kotlin Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Kotlin Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

목표: 실용적인 DSL

Kotlin으로 최소한이지만 실제적인 HTML 빌더 DSL을 만듭니다. 동일한 패턴을 모든 구성, 테스트 픽스처 또는 보고서 빌더에 적용할 수 있습니다. 그 결과 문자열 연결을 대체하는 타입 안전하고 IDE 친화적인 API를 만들 수 있습니다.

Tag 기본 클래스 정의하기

모든 HTML 요소는 이름, 속성 및 자식 요소라는 공통 구조를 공유합니다. 다음과 같이 기본 클래스부터 시작합니다.

open class Tag(val name: String) {
    val attrs = mutableMapOf<String, String>()
    val children = mutableListOf<Tag>()
    fun render(indent: Int = 0): String {
        val pad = " ".repeat(indent)
        val attrStr = if (attrs.isEmpty()) "" else " " + attrs.entries.joinToString(" ") { "${it.key}=\"${it.value}\"" }
        val body = children.joinToString("\n") { it.render(indent + 2) }
        return "$pad<$name$attrStr>\n$body\n$pad</$name>"
    }
}

@DslMarker 적용하기

모든 빌더 클래스에 표시하여 내부 범위에서 바깥 범위의 메서드를 실수로 호출하지 못하게 합니다.

@DslMarker
annotation class HtmlDsl

@HtmlDsl class Html : Tag("html")
@HtmlDsl class Head : Tag("head")
@HtmlDsl class Body : Tag("body")
@HtmlDsl class Div  : Tag("div")
@HtmlDsl class P   : Tag("p")

빌더 함수 추가하기

각 태그 클래스에 자식 태그를 생성하고, 블록을 적용한 다음, 자식 요소에 추가하는 확장 함수를 만듭니다.

fun Html.head(block: Head.() -> Unit) = Head().also { it.block(); children += it }
fun Html.body(block: Body.() -> Unit) = Body().also { it.block(); children += it }
fun Body.div(block: Div.() -> Unit) = Div().also { it.block(); children += it }
fun Div.p(text: String) = P().also { it.attrs["text"] = text; children += it }

최상위 html 빌더

루트 요소를 생성하고 사용자 블록을 적용하는 최상위 진입점을 제공합니다.

fun html(block: Html.() -> Unit): Html {
    val root = Html()
    root.block()
    return root
}

DSL 사용하기

그 결과 깔끔하고 읽기 쉬운 DSL이 만들어집니다.

val page = html {
    head { }
    body {
        div {
            p("Hello, DSL!")
        }
    }
}
println(page.render())

속성 추가하기

임의의 속성을 자연스럽게 설정할 수 있도록 attr 도우미를 추가합니다.

fun Tag.attr(key: String, value: String) { attrs[key] = value }

// Usage
div {
    attr("class", "container")
    p("Content")
}

구성 DSL 패턴

동일한 패턴을 구성 객체에도 적용할 수 있습니다. HTML 태그 대신 도메인 클래스를 사용합니다.

class ServerConfig {
    var host = "localhost"
    var port = 8080
    var db: DbConfig? = null
    fun database(block: DbConfig.() -> Unit) { db = DbConfig().apply(block) }
}
fun server(block: ServerConfig.() -> Unit) = ServerConfig().apply(block)

중첩 및 조합

각 빌더 함수가 생성한 객체를 반환하므로 빌더를 자유롭게 조합할 수 있습니다. DSL의 중첩 깊이는 데이터 계층 구조의 깊이와 일치합니다.

타입을 통한 오류 방지

타입 시스템이 구조를 적용합니다. Head에는 body 확장 함수가 없으므로 Head 안에서 body { }를 호출할 수 없습니다. 잘못된 구조는 컴파일 시 오류가 됩니다.

렌더링 및 테스트

DSL이 일반 Kotlin 객체 트리를 생성하므로 렌더링과 테스트는 간단합니다. render()를 호출하고 출력 문자열을 확인하거나, 테스트에서 객체 트리를 순회하면 됩니다.

나중에 DSL 확장하기

새 태그나 구성 옵션을 추가하려면 적절한 수신 클래스에 새 확장 함수만 추가하면 됩니다. 기존 호출부는 영향을 받지 않으므로 실제로 개방-폐쇄 원칙이 적용됩니다.

빠른 확인

Kotlin HTML/구성 DSL을 "타입 안전"하게 만드는 요소는 무엇인가요?

요약: 타입 안전한 DSL 구축하기

핵심 단계:

  • 계층 구조의 각 수준에 맞는 빌더 클래스를 정의합니다
  • 수신 객체가 의도하지 않게 누출되지 않도록 @DslMarker를 적용합니다
  • 자식 객체를 생성하고 구성한 후 추가하는 확장 함수를 작성합니다
  • 최상위 진입점 함수를 노출합니다
  • 렌더링과 검증은 일반 Kotlin 객체를 대상으로 수행합니다

자주 묻는 질문

“타입 안전한 HTML/Config DSL 만들기” 강의는 무료인가요?

네 — “타입 안전한 HTML/Config DSL 만들기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Kotlin Academy 강의 전체를 잠금 해제할 수 있습니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“타입 안전한 HTML/Config DSL 만들기”에서 뭘 배우나요?

빌더 패턴과 확장 람다를 사용해 간단한 설정 DSL을 구현해 보세요. 브라우저에서 직접 실행하는 실습 코드로 Kotlin Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Kotlin Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Kotlin Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“타입 안전한 HTML/Config DSL 만들기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Kotlin Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Kotlin Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 수신 객체가 있는 람다: DSL의 기반
  2. @DslMarker: 수신 객체 누출 방지
  3. 타입 안전한 HTML/Config DSL 만들기
  4. 사용자를 방해하지 않고 DSL 테스트하고 발전시키기
← Kotlin Academy(으)로 돌아가기