프로그래밍언어

[Swift] Swift의 DSL(Domain-Specific-Language) 설계 및 구현

애기공룡훈련병 2025. 2. 16. 07:03
반응형

1. DSL(Domain-Specific Language)

DSL(Domain-Specific Language)은 특정 도메인에 특화된 언어로, 특정 문제를 보다 직관적이고 효율적으로 해결할 수 있도록 설계됩니다. 범용 프로그래밍 언어(General-Purpose Language, GPL)와는 달리, 특정 작업을 수행하는 데 초점을 맞춘 것이 특징입니다.

DSL의 장점

  • 가독성 향상: 도메인 전문가가 코드의 의미를 쉽게 이해할 수 있음
  • 생산성 증가: 특정 문제를 해결하는 데 필요한 코드량을 줄여 빠르게 개발 가능
  • 추상화 제공: 내부 구현을 숨기고 도메인과 직결된 개념을 제공
  • 오류 감소: 특정 도메인에서 자주 발생하는 실수를 방지하는 구조 설계 가능

2. Swift에서 DSL 구현 방법

Swift에서는 함수형 프로그래밍 기능과 연산자 오버로딩, 제네릭, 프로토콜 확장 등을 활용하여 DSL을 구현할 수 있습니다. 특히 Result Builder를 활용하면 SwiftUI처럼 선언형 문법을 구성하는 DSL을 쉽게 만들 수 있습니다.

Result Builder

Result Builder는 Swift 5.4에서 도입된 기능으로, 여러 개의 값을 조합하여 하나의 결과 값을 생성할 때 유용합니다. SwiftUI의 @ViewBuilder가 대표적인 예시입니다.

Result Builder를 활용한 DSL 설계 사례

아래는 HTML을 Swift DSL로 작성할 수 있도록 HTMLBuilder를 구현하는 예제입니다.

Swift DSL을 활용한 HTML 마크업 빌더

@resultBuilder
struct HTMLBuilder {
    static func buildBlock(_ components: String...) -> String {
        components.joined(separator: "\n")
    }
}

struct HTML {
    let content: String
    init(@HTMLBuilder _ content: () -> String) {
        self.content = content()
    }
    func render() -> String {
        "<html>\n\(content)\n</html>"
    }
}

struct Body {
    let content: String
    init(@HTMLBuilder _ content: () -> String) {
        self.content = content()
    }
    func render() -> String {
        "<body>\n\(content)\n</body>"
    }
}

struct Paragraph {
    let text: String
    func render() -> String {
        "<p>\(text)</p>"
    }
}

// DSL을 활용한 HTML 문서 생성
let html = HTML {
    Body {
        Paragraph(text: "Hello, Swift DSL!").render()
    }.render()
}.render()

print(html)

실행 결과

<html>
<body>
<p>Hello, Swift DSL!</p>
</body>
</html>

Result Builder를 활용한 SwiftUI 스타일 DSL

SwiftUI는 @ViewBuilder를 사용하여 DSL을 설계한 대표적인 예시입니다. 비슷한 방식으로 JSON, SQL, UI 레이아웃 등을 선언형 문법으로 작성할 수 있습니다.

3. DSL의 활용 사례

Swift에서 DSL을 활용할 수 있는 대표적인 사례는 다음과 같습니다.

SwiftUI

SwiftUI는 @ViewBuilder를 이용하여 선언형 UI를 구성하는 DSL의 대표적인 예시입니다.

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Hello, SwiftUI")
                .font(.title)
            Button("Click Me") {
                print("Button Clicked!")
            }
        }
    }
}

JSON 빌더 DSL

@resultBuilder
struct JSONBuilder {
    static func buildBlock(_ components: String...) -> String {
        "{ " + components.joined(separator: ", ") + " }"
    }
}

func json(@JSONBuilder _ content: () -> String) -> String {
    return content()
}

let jsonData = json {
    "\"name\": \"John Doe\""
    "\"age\": 30"
}

print(jsonData)

SQL Query DSL

struct SQL {
    private var query: String
    init(_ query: String) {
        self.query = query
    }
    func render() -> String {
        query
    }
}

@resultBuilder
struct SQLBuilder {
    static func buildBlock(_ components: String...) -> String {
        components.joined(separator: " ")
    }
}

func select(@SQLBuilder _ query: () -> String) -> SQL {
    SQL("SELECT " + query())
}

let sqlQuery = select {
    "id, name"
    "FROM users"
    "WHERE age > 30"
}.render()

print(sqlQuery)

실행 결과

SELECT id, name FROM users WHERE age > 30

 

Swift의 Result Builder를 활용하면 선언형 DSL을 쉽게 만들 수 있습니다. 이를 통해 SwiftUI 같은 UI 프레임워크뿐만 아니라, JSON 생성기, SQL 쿼리 빌더, HTML 빌더 등 다양한 분야에서 간결하고 직관적인 DSL을 설계할 수 있습니다.

 

결과적으로 Swift DSL을 활용하면

  • 코드의 가독성이 향상되고,
  • 특정 도메인 문제를 쉽게 해결할 수 있으며,
  • 추상화 수준을 높여 유지보수를 쉽게 할 수 있습니다.
반응형