CHAP10 - Modern-Java-in-Action/Online-Study GitHub Wiki

Chapter 10 ๋žŒ๋‹ค๋ฅผ ์ด์šฉํ•œ ๋„๋ฉ”์ธ ์ „์šฉ ์–ธ์–ด

์ด์žฅ์˜ ๋‚ด์šฉ

  • ๋„๋ฉ”์ธ ์ „์šฉ ์–ธ์–ด(Domain-Specific Languages, DSL)๋ž€ ๋ฌด์—‡์ด๋ฉฐ ์–ด๋–ค ํ˜•์‹์œผ๋กœ ๊ตฌ์„ฑ๋˜๋Š”๊ฐ€?
  • DSL์„ API์— ์ถ”๊ฐ€ํ•  ๋•Œ์˜ ์žฅ๋‹จ์ 
  • JVM์—์„œ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ž๋ฐ” ๊ธฐ๋ฐ˜ DSL์„ ๊น”๋”ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋Œ€์•ˆ
  • ์ตœ์‹  ์ž๋ฐ” ์ธํ„ฐํŽ˜์ด์Šค์™€ ํด๋ž˜์Šค์— ์ ์šฉ๋œ DSL์—์„œ ๋ฐฐ์›€
  • ํšจ๊ณผ์ ์ธ ์ž๋ฐ” ๊ธฐ๋ฐ˜ DSL์„ ๊ตฌํ˜„ํ•˜๋Š” ํŒจํ„ด๊ณผ ๊ธฐ๋ฒ•
  • ์ด๋“ค ํŒจํ„ด์„ ์ž๋ฐ” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๋„๊ตฌ์—์„œ ์–ผ๋งˆ๋‚˜ ํ”ํžˆ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

ํ”„๋กœ๊ทธ๋žจ์€ ์‚ฌ๋žŒ๋“ค์ด ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ์ž‘์„ฑ๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋ฉฐ ๊ธฐ๊ธฐ๊ฐ€ ์‹คํ–‰ํ•˜๋Š” ๋ถ€๋ถ„์€ ๋ถ€์ฐจ์ ์ผ ๋ฟ - ํ•˜๋กค๋“œ ์•„๋ฒจ์Šจ

  • ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋„ ๊ฒฐ๊ตญ ์–ธ์–ด์ด๋ฉฐ ์–ธ์–ด์˜ ์ฃผ์š” ๋ชฉํ‘œ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๋ช…ํ™•ํ•˜๊ณ  ์•ˆ์ •์ ์ธ ๋ฐฉ์‹์œผ๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ
  • ์˜๋„๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌ๋˜์–ด์•ผ ํ•œ๋‹ค.
  • DSL
    • ํŠน์ • ๋„๋ฉ”์ธ์„ ๋Œ€์ƒ์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ํŠน์ˆ˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด
    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํ‘œํ˜„
    • ๋„๋ฉ”์ธ ์ „๋ฌธ๊ฐ€๊ฐ€ ๋น„์ฆˆ๋‹ˆ์Šค ๊ด€์ ์—์„œ ์†Œํ”„ํŠธ์›จ์–ด๊ฐ€ ์ œ๋Œ€๋กœ ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Œ
  • ๋ฉ”์ด๋ธ, ์•คํŠธ๋Š” ๋นŒ๋“œ ๊ณผ์ •์„ ํ‘œํ˜„ํ•˜๋Š” DSL, HTML์€ ์›นํŽ˜์ด์ง€์˜ ๊ตฌ์กฐ๋ฅผ ์ •์˜ํ•˜๋„๋ก ํŠนํ™”๋œ ์–ธ์–ด

10.1 ๋„๋ฉ”์ธ ์ „์šฉ ์–ธ์–ด

๋„๋ฉ”์ธ ์ „์šฉ ์–ธ์–ด (domain-specific language, DSL)

  • ํŠน์ • ๋น„์ฆˆ๋‹ˆ์Šค ๋„๋ฉ”์ธ์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ๋งŒ๋“  ์–ธ์–ด
    • ex) ํšŒ๊ณ„์ „์šฉ ์†Œํ”„ํŠธ์›จ์–ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœ -> ๋น„์ฆˆ๋‹ˆ์Šค ๋„๋ฉ”์ธ์—๋Š” ํ†ต์žฅ ์ž…์ถœ๊ธˆ ๋‚ด์—ญ, ๊ณ„์ขŒ ์™€ ๊ฐ™์€ ๊ฐœ๋…์ด ํฌํ•จ
  • ํŠน์ • ๋น„์ฆˆ๋‹ˆ์Šค ๋„๋ฉ”์ธ์„ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋งŒ๋“  API

DSL์˜ ์žฅ์ 

  • ๊ฐ„๊ฒฐํ•จ : API๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๊ฐ„ํŽธํ•˜๊ฒŒ ์บก์Аํ™”ํ•˜๋ฏ€๋กœ ๋ฐ˜๋ณต์„ ํ”ผํ•  ์ˆ˜ ์žˆ๊ณ  ์ฝ”๋“œ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
  • ๊ฐ€๋…์„ฑ : ๋„๋ฉ”์ธ ์˜์—ญ์˜ ์šฉ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋น„ ๋„๋ฉ”์ธ ์ „๋ฌธ๊ฐ€๋„ ์ฝ”๋“œ๋ฅผ ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋‹ค์–‘ํ•œ ์กฐ์ง ๊ตฌ์„ฑ์› ๊ฐ„์— ์ฝ”๋“œ์™€ ๋„๋ฉ”์ธ ์˜์—ญ์ด ๊ณต์œ ๋  ์ˆ˜ ์žˆ๋‹ค.
  • ์œ ์ง€๋ณด์ˆ˜ : ์ž˜ ์„ค๊ณ„๋œ DSL๋กœ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ๋Š” ์‰ฝ๊ฒŒ ์œ ์ง€ ๋ณด์ˆ˜ํ•˜๊ณ  ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.
  • ๋†’์€ ์ˆ˜์ค€์˜ ์ถ”์ƒํ™” : DSL์€ ๋„๋ฉ”์ธ๊ณผ ๊ฐ™์€ ์ถ”์ƒํ™” ์ˆ˜์ค€์—์„œ ๋™์ž‘ํ•˜๋ฏ€๋กœ ๋„๋ฉ”์ธ์˜ ๋ฌธ์ œ์™€ ์ง์ ‘์ ์œผ๋กœ ๊ด€๋ จ๋˜์ง€ ์•Š์€ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ์ˆจ๊ธด๋‹ค.
  • ์ง‘์ค‘ : ๋น„์ฆˆ๋‹ˆ์Šค ๋„๋ฉ”์ธ์˜ ๊ทœ์น™์„ ํ‘œํ˜„ํ•  ๋ชฉ์ ์œผ๋กœ ์„ค๊ณ„๋œ ์–ธ์–ด์ด๋ฏ€๋กœ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ํŠน์ • ์ฝ”๋“œ์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ์ƒ์‚ฐ์„ฑ์ด ์ข‹์•„์ง„๋‹ค.
  • ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ : ์ง€์ •๋œ ์–ธ์–ด๋กœ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํ‘œํ˜„ํ•จ์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ธํ”„๋ผ๊ตฌ์กฐ์™€ ๊ด€๋ จ๋œ ๋ฌธ์ œ์™€ ๋…๋ฆฝ์ ์œผ๋กœ ๋น„์ฆˆ๋‹ˆ์Šค ๊ด€๋ จ๋œ ์ฝ”๋“œ์—์„œ ์ง‘์ค‘ํ•˜๊ธฐ๊ฐ€ ์šฉ์ดํ•˜๋‹ค.

DSL์˜ ๋‹จ์ 

  • DSL ์„ค๊ณ„์˜ ์–ด๋ ค์›€ : ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ œํ•œ์ ์ธ ์–ธ์–ด์— ๋„๋ฉ”์ธ ์ง€์‹์„ ๋‹ด๋Š” ๊ฒƒ์ด ์‰ฌ์šด ์ž‘์—…์€ ์•„๋‹ˆ๋‹ค.
  • ๊ฐœ๋ฐœ ๋น„์šฉ : ์ฝ”๋“œ์— DSL์„ ์ถ”๊ฐ€ํ•˜๋Š” ์ž‘์—…์€ ์ดˆ๊ธฐ ํ”„๋กœ์ ํŠธ์— ๋งŽ์€ ๋น„์šฉ๊ณผ ์‹œ๊ฐ„์ด ์†Œ๋ชจ๋œ๋‹ค. ๋˜ํ•œ DSL ์œ ์ง€๋ณด์ˆ˜์™€ ๋ณ€๊ฒฝ์€ ํ”„๋กœ์ ํŠธ์— ๋ถ€๋‹ด์„ ์ฃผ๋Š” ์š”์†Œ๋‹ค.
  • ์ถ”๊ฐ€ ์šฐํšŒ ๊ณ„์ธต : DSL์€ ์ถ”๊ฐ€์ ์ธ ๊ณ„์ธต์œผ๋กœ ๋„๋ฉ”์ธ ๋ชจ๋ธ์„ ๊ฐ์‹ธ๋ฉฐ ์ด๋•Œ ๊ณ„์ธต์„ ์ตœ๋Œ€ํ•œ ์ž‘๊ฒŒ ๋งŒ๋“ค์–ด ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ํšŒํ”ผํ•œ๋‹ค.
  • ์ƒˆ๋กœ ๋ฐฐ์›Œ์•ผ ํ•˜๋Š” ์–ธ์–ด : DSL์„ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€ํ•˜๋ฉด์„œ ํŒ€์ด ๋ฐฐ์›Œ์•ผ ํ•˜๋Š” ์–ธ์–ด๊ฐ€ ํ•œ ๊ฐœ ๋” ๋Š˜์–ด๋‚œ๋‹ค๋Š” ๋ถ€๋‹ด์ด ์žˆ๋‹ค.
  • ํ˜ธ์ŠคํŒ… ์–ธ์–ด ํ•œ๊ณ„ : ์ผ๋ถ€ ์ž๋ฐ” ๊ฐ™์€ ๋ฒ”์šฉ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋Š” ์žฅํ™ฉํ•˜๊ณ  ์—„๊ฒฉํ•œ ๋ฌธ๋ฒ•์„ ๊ฐ€์กŒ๋‹ค. ์ด๋Ÿฐ ์–ธ์–ด๋กœ๋Š” ์‚ฌ์šฉ์ž ์นœํ™”์  DSL์„ ๋งŒ๋“ค๊ธฐ๊ฐ€ ํž˜๋“ค๋‹ค.

10.1.2 JVM์—์„œ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค๋ฅธ DSL ํ•ด๊ฒฐ์ฑ…

  • DSL์˜ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๊ตฌ๋ถ„ํ•˜๋Š” ๋ฐฉ๋ฒ• -> ๋‚ด๋ถ€ DSL, ์™ธ๋ถ€ DSL, ๋‹ค์ค‘ DSL

๋‚ด๋ถ€ DSL

  • ์ž๋ฐ”๋กœ ๊ตฌํ˜„ํ•œ DSL์„ ์˜๋ฏธ
  • ๋žŒ๋‹ค ํ‘œํ˜„์‹์˜ ๋“ฑ์žฅ์œผ๋กœ ์ฝ๊ธฐ ์‰ฝ๊ณ , ๊ฐ„๋‹จํ•˜๋ฉฐ ํ‘œํ˜„๋ ฅ ์žˆ๋Š” DSL์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒ ๋จ
  • ์ต๋ช… ๋‚ด๋ถ€ ํด๋ž˜์Šค ๋Œ€์‹  ๋žŒ๋‹ค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์žฅํ™ฉํ•จ์„ ํฌ๊ฒŒ ์ค„์—ฌ ์‹ ํ˜ธ ๋Œ€๋น„ ์žก์Œ ๋น„์œจ์„ ์ ์ • ์ˆ˜์ค€์œผ๋กœ ์œ ์ง€ํ•˜๋Š” DSL์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
// forEach๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฌธ์ž์—ด ๋ชฉ๋ก ์ถœ๋ ฅํ•˜๊ธฐ 
List<String> numbers = Arrays.asList("one", "two", "three");

// 1. ์ต๋ช… ๋‚ด๋ถ€ ํด๋ž˜์Šค
numbers.forEach(new Consumer<String>() {    -> ์ฝ”๋“œ์˜ ์žก์Œ1 
    @Override  
    public void accept(String s) {          -> ์ฝ”๋“œ์˜ ์žก์Œ2
        System.out.println(s);              -> ์ฝ”๋“œ์˜ ์žก์Œ3
    }  
});

// 2. ๋žŒ๋‹ค ํ‘œํ˜„์‹
numbers.forEach(s -> System.out.println(s));

// 3. ๋ฉ”์„œ๋“œ ์ฐธ์กฐ
numbers.forEach(System.out::println);
  • ์™ธ๋ถ€ DSL์— ๋น„ํ•ด ์ƒˆ๋กœ์šด ํŒจํ„ด๊ณผ ๊ธฐ์ˆ ์„ ๋ฐฐ์›Œ DSL์„ ๊ตฌํ˜„ํ•˜๋Š” ๋…ธ๋ ฅ์ด ์ค„์–ด๋“ ๋‹ค
  • ์ˆœ์ˆ˜ ์ž๋ฐ”๋กœ DSL์„ ๊ตฌํ˜„ํ•˜๋ฉด ๋‚˜๋จธ์ง€ ์ฝ”๋“œ์™€ ํ•จ๊ป˜ DSL์„ ์ปดํŒŒ์ผํ•  ์ˆ˜ ์žˆ๋‹ค
  • ๊ฐœ๋ฐœํŒ€์ด ์ƒˆ๋กœ์šด ์–ธ์–ด๋ฅผ ๋ฐฐ์šธ ํ•„์š”๊ฐ€ ์—†๋‹ค.
  • ๊ธฐ์กด ์ž๋ฐ” IDE๋ฅผ ํ†ตํ•ด ์ž๋™ ์™„์„ฑ, ์ž๋™ ๋ฆฌํŒฉํ„ฐ๋ง ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ•œ ๊ฐœ์˜ ์–ธ์–ด๋กœ ํ•˜๋‚˜ ๋˜๋Š” ์—ฌ๋Ÿฌ ๋„๋ฉ”์ธ์„ ๋Œ€์‘ํ•˜์ง€ ๋ชปํ•ด ์ถ”๊ฐ€ DSL์„ ๊ฐœ๋ฐœํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์ž๋ฐ”๋ฅผ ์ด์šฉํ•˜์—ฌ ์ถ”๊ฐ€ DSL์„ ์‰ฝ๊ฒŒ ํ•ฉ์น ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์ค‘ DSL

์žฅ์ 

  • ๊ฐ™์€ ์ž๋ฐ” ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” JVM ๊ธฐ๋ฐ˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋ฅผ ์ด์šฉํ•˜์—ฌ DSL์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฌธ๋ฒ•์  ์žก์Œ์ด ์—†์œผ๋ฉฐ ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹Œ ์‚ฌ๋žŒ๋„ ์ฝ”๋“œ๋ฅผ ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ž๋ฐ” ์–ธ์–ด๊ฐ€ ๊ฐ€์ง€๋Š” ํ•œ๊ณ„๋ฅผ ๋„˜์„ ์ˆ˜ ์žˆ๋‹ค (์Šค์นผ๋ผ - ์ปค๋ง, ์ž„์˜ ๋ณ€ํ™˜ ๋“ฑ DSL ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ์—ฌ๋Ÿฌ ํŠน์„ฑ์„ ๊ฐ–์ถค)

๋‹จ์ 

  • ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ํ•ด๋‹น ์–ธ์–ด์— ๋Œ€ํ•ด ๊ณ ๊ธ‰ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ์ •๋„์˜ ์ถฉ๋ถ„ํ•œ ์ง€์‹์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • ๋‘ ๊ฐœ ์ด์ƒ์˜ ์–ธ์–ด๊ฐ€ ํ˜ผ์žฌํ•˜๋ฏ€๋กœ ์—ฌ๋Ÿฌ ์ปดํŒŒ์ผ๋Ÿฌ๋กœ ์†Œ์Šค๋ฅผ ๋นŒ๋“œํ•˜๋„๋ก ๋นŒ๋“œ ๊ณผ์ •์„ ๊ฐœ์„ ํ•ด์•ผ ํ•œ๋‹ค.
  • ํ˜ธํ™˜์„ฑ ๋ฌธ์ œ๋ฅผ ๊ณ ๋ คํ•ด์•ผํ•œ๋‹ค

์™ธ๋ถ€ DSL

  • ์ž์‹ ๋งŒ์˜ ๋ฌธ๋ฒ•๊ณผ ๊ตฌ๋ฌธ์œผ๋กœ ์ƒˆ๋กœ์šด ์–ธ์–ด๋ฅผ ์„ค๊ณ„ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๋‹จ์ 
  • ์šฐ๋ฆฌ์—๊ฒŒ ํ•„์š”ํ•œ ํŠน์„ฑ์„ ์™„๋ฒฝํ•˜๊ฒŒ ์ œ๊ณตํ•˜๋Š” ์–ธ์–ด๋ฅผ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ 

10.2 ์ตœ์‹  ์ž๋ฐ” API์˜ ์ž‘์€ DSL

  • ์ž๋ฐ”์˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์˜ ์žฅ์ ์„ ์ ์šฉํ•œ ์ฒซ API๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ์ž๋ฐ” API ์ž์‹ ์ด๋‹ค.
  • ๋žŒ๋‹ค ํ‘œํ˜„์‹๊ณผ ๋ฉ”์†Œ๋“œ ์ฐธ์กฐ๋ฅผ ์ด์šฉํ•ด DSL์˜ ๊ฐ€๋…์„ฑ, ์žฌ์‚ฌ์šฉ์„ฑ, ๊ฒฐํ•ฉ์„ฑ์ด ๋†’์•„์กŒ๋‹ค.

์‚ฌ๋žŒ๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฆฌ์ŠคํŠธ์—์„œ ๋‚˜์ด์ˆœ์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ •๋ ฌํ•˜๋Š” ์˜ˆ์ œ

Collections.sort(persons, new Comparator<Person>() {
  public int compare(Person p1, Person p2) {
    return p1.getAge() - p2.getAge();
  }
});
  • java8 ์ด์ „์—๋Š” ์œ„์™€ ๊ฐ™์ด ์ต๋ช… ํด๋ž˜์Šค๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ตฌํ˜„ -> ๋žŒ๋‹ค ํ‘œํ˜„์‹์œผ๋กœ ๋ณ€๊ฒฝ
Collections.sort(persons, (p1, p2) -> p1.getAge() - p2.getAge());
  • ์ •์  ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ฉ”์„œ๋“œ ์ง‘ํ•ฉ๊ณผ ๋ฉ”์„œ๋“œ ์ฐธ์กฐ ์ œ๊ณต
Collections.sort(persons, comparing(p -> p.getAge()));
Collections.sort(persons, comparing(Person::getAge));
  • reverse ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ญ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜๊ฑฐ๋‚˜ ์ด๋ฆ„์œผ๋กœ ๋น„๊ต๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” Comparator๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ์•ŒํŒŒ๋ฒณ ์ˆœ ์ •๋ ฌ
Collections.sort(persons, comparing(Person::getAge).reverse());
Collections.sort(persons, comparing(Person::getAge)
                          .thenComparing(Person::getName));
  • List ์ธํ„ฐํŽ˜์ด์Šค์— ์ถ”๊ฐ€๋œ ์ƒˆ sort ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ์ฝ”๋“œ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌ
persons.sort(comparing(Person::getAge)
                          .thenComparing(Person::getName));
  • ์ปฌ๋ ‰์…˜ ์ •๋ ฌ ๋„๋ฉ”์ธ์˜ ์ตœ์†Œ DSL
  • ์ž‘์€ ์˜์—ญ์— ๊ตญํ•œ๋œ ์˜ˆ์ œ์ง€๋งŒ ์ด๋ฏธ ๋žŒ๋‹ค์™€ ๋ฉ”์„œ๋“œ ์ฐธ์กฐ๋ฅผ ์ด์šฉํ•œ DSL์ด ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ, ์žฌ์‚ฌ์šฉ์„ฑ, ๊ฒฐํ•ฉ์„ฑ์„ ๋†’์ผ์ˆ˜ ์žˆ๋Š”์ง€ ๋ณด์—ฌ์ค€๋‹ค.

10.2.1 ์ŠคํŠธ๋ฆผ API๋Š” ์ปฌ๋ ‰์…˜์„ ์กฐ์ž‘ํ•˜๋Š” DSL

  • Stream ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ์ž๋ฐ” API์— ์ž‘์€ ๋‚ด๋ถ€ DSL์„ ์ ์šฉํ•œ ์ข‹์€ ์˜ˆ์‹œ
    • ๋ฐ์ดํ„ฐ ์กฐ์ž‘(ํ•„ํ„ฐ๋ง, ์ •๋ ฌ, ๋ณ€ํ™˜, ๊ทธ๋ฃนํ™” ๋“ฑ) ๊ธฐ๋Šฅ ์ œ๊ณต

๋ฐ˜๋ณต ํ˜•์‹์œผ๋กœ ์˜ˆ์ œ ๋กœ๊ทธ ํŒŒ์ผ์—์„œ ์—๋Ÿฌ ํ–‰์„ ์ฝ๋Š” ์ฝ”๋“œ

List<String> errors = new ArrayList<>();
int errorCount = 0;
BufferedReader bufferedReader = new BufferedReader(new FileReader(fileName));
String line = bufferedReader.readLine();
while (errorCount < 40 && line != null) {
    if (line.startsWith("ERROR")) {
        errors.add(line);
        errorCount++;
    }
    line = bufferedReader.readLine();
}
  • ์ฝ”๋“œ๊ฐ€ ์žฅํ™ฉํ•˜์—ฌ ์˜๋„๋ฅผ ํ•œ ๋ˆˆ์— ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ต๊ณ , ๋ฌธ์ œ๊ฐ€ ๋ถ„๋ฆฌ๋˜์ง€ ์•Š์•„ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ ๋ชจ๋‘ ์ €ํ•˜๋จ

ํ•จ์ˆ˜ํ˜•์œผ๋กœ ๋กœ๊ทธ ํŒŒ์ผ์˜ ์—๋Ÿฌ ํ–‰์„ ์ฝ๋Š” ์ฝ”๋“œ

List<String> errors = Files.lines(Paths.get(fileName))
                                        .filter(line -> line.startsWith("ERROR"))
                                        .limit(40)
                                        .collect(toList());
  • ์ŠคํŠธ๋ฆผ API์˜ ํ”Œ๋ฃจ์–ธํŠธ ์Šคํƒ€์ผ์ธ ๋ฉ”์„œ๋“œ ์ฒด์ธ์€ ์ž˜ ์„ค๊ณ„๋œ DSL์˜ ๋˜ ๋‹ค๋ฅธ ํŠน์ง•
    • ๋ชจ๋“  ์ค‘๊ฐ„ ์—ฐ์‚ฐ์€ ๊ฒŒ์œผ๋ฅด๋ฉฐ ๋‹ค๋ฅธ ์—ฐ์‚ฐ์œผ๋กœ ํŒŒ์ดํ”„๋ผ์ธ๋  ์ˆ˜ ์žˆ๋Š” ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ฐ˜ํ™˜
    • ์ตœ์ข… ์—ฐ์‚ฐ์€ ์ ๊ทน์ ์ด๋ฉฐ ์ „์ฒด ํŒŒ์ดํ”„๋ผ์ธ์ด ๊ณ„์‚ฐ์„ ์ผ์œผํ‚จ๋‹ค.

10.2.2 ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” DSL์ธ Collectors

  • Collector ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” DSL
  • ์ฐจ๋ฅผ ๋ธŒ๋žœ๋“œ์™€ ์ƒ‰์ƒ์œผ๋กœ ๊ทธ๋ฃนํ™”ํ•˜๋Š” ๋กœ์ง
// ์ค‘์ฒฉํ˜•์‹
Map<String, Map<Color, List<Car>>> carsByBrandAndColor 
        = cars.stream().collect(groupingBy(Car::getBrand,
                                groupingBy(Car::getColor)));
                
// ํ”Œ๋ฃจ์–ธํŠธ ๋ฐฉ์‹
Comparator<Person> comparator = 
        comparing(Person::getAge).thenComparing(Person::getName);
  • ์…‹ ์ด์ƒ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์กฐํ•ฉํ•  ๋•Œ๋Š” ๋ณดํ†ต ํ”Œ๋ฃจ์–ธํŠธ ํ˜•์‹์ด ์ค‘์ฒฉ ํ˜•์‹์— ๋น„ํ•ด ๊ฐ€๋…์„ฑ์ด ์ข‹์Œ
  • groupingBy ํŒฉํ„ฐ๋ฆฌ ๋ฉ”์„œ๋“œ์— ์ž‘์—…์„ ์œ„์ž„ํ•˜๋Š” GroupingBuilder๋ฅผ ๋งŒ๋“ค์–ด ์œ ์—ฐํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ทธ๋ฃนํ™” ์ž‘์—… ๊ฐ€๋Šฅ
import static java.util.stream.Collectors.groupingBy;
public class GroupingBuilder<T, D, K> {
    private final Collector<? super T, ?, Map<K, D>> collector;

    private GroupingBuilder(Collector<? super T, ?, Map<K, D>> collector) {
        this.collector = collector;
    }

    public Collector<? super T, ?, Map<K, D>> get() {
        return collector;
    }
    
    public <J> GroupingBuilder<T, Map<K, D>, J> 
            after(Function<? super T, ? extends J> classifier) {
        return new GroupingBuilder<>(groupingBy(classifier, collector));
    }
    
    public static <T, D, K> GroupingBuilder<T, List<T>, K> 
            groupOn(Function<? super T, ? extends K> classifier) {
        return new GroupingBuilder<>(groupingBy(classifier));
    }
}
  • ํ”Œ๋ฃจ์–ธํŠธ ํ˜•์‹ ๋นŒ๋” ์‚ฌ์šฉ์‹œ ์ค‘์ฒฉ๋œ ๊ทธ๋ฃนํ™” ์ˆ˜์ค€์— ๋ฐ˜๋Œ€๋กœ ๊ทธ๋ฃนํ™” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ด์•ผํ•จ -> ์ง๊ด€์ ์ด์ง€ ๋ชปํ•จ
Collector<? super Car, ?, Map<Brand, Map<Color, List<Car>>>> 
    carGroupingCollector = 
        GroupingBuilder.groupOn(Car::getColor)
        .after(Car::getBrand).get();

10.3 ์ž๋ฐ”๋กœ DSL์„ ๋งŒ๋“œ๋Š” ํŒจํ„ด๊ณผ ๊ธฐ๋ฒ•

10.3.1 ๋ฉ”์„œ๋“œ ์ฒด์ธ

  • ์ž๋ฐ”์˜ ๋ณต์žกํ•œ ๋ฃจํ”„ ์ œ์–ด์™€ ๋น„๊ตํ•ด ์œ ์ฐฝํ•จ์„ ์˜๋ฏธํ•˜๋Š” ํ”Œ๋ฃจ์–ธํŠธ ์Šคํƒ€์ผ์˜ ๋ฉ”์„œ๋“œ ์ฒด์ธ์„ ์ด์šฉํ•˜์—ฌ DSL์„ ๋งŒ๋“  ๊ฒƒ

์žฅ์ 

  • ์ฃผ๋ฌธ์— ์‚ฌ์šฉํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋นŒ๋” ๋‚ด๋ถ€๋กœ ๊ตญํ•œ๋œ๋‹ค
  • ์ •์  ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ์„ ์ตœ์†Œํ™”ํ•˜๊ณ  ๋ฉ”์„œ๋“œ ์ด๋ฆ„์ด ์ธ์ˆ˜์˜ ์ด๋ฆ„์„ ๋Œ€์‹ ํ•˜๋„๋ก ๋งŒ๋“ฆ์œผ๋กœ์„œ DSL ๊ฐ€๋…์„ฑ์„ ๊ฐœ์„ ํ•˜๋Š” ํšจ๊ณผ
  • ์ด๋Ÿฐ ๊ธฐ๋ฒ•์„ ์ ์šฉํ•œ ํ”Œ๋ฃจ์–ธํŠธ DSL์—๋Š” ๋ถ„๋ฒ•์  ์žก์Œ์ด ์ตœ์†Œํ™”

๋‹จ์ 

  • ๋นŒ๋”๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค
  • ์ƒ์œ„๋‹ค ์ˆ˜์ค€์˜ ๋นŒ๋”๋ฅผ ํ•˜์œ„ ์ˆ˜์ค€์˜ ๋นŒ๋”์™€ ์—ฐ๊ฒฐํ•  ์ ‘์ฐฉ ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค
  • ๋„๋ฉ”์ธ ๊ฐ์ฒด ์ค‘์ฒฉ๊ตฌ์กฐ์™€ ์ผ์น˜ํ•˜๊ฒŒ ๋“ค์—ฌ์“ฐ๊ธฐ๋ฅผ ๊ฐ•์ œํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์—†์Œ

10.3.2 ์ค‘์ฒฉ๋œ ํ•จ์ˆ˜ ์ด์šฉ

  • ๋‹ค๋ฅธ ํ•จ์ˆ˜ ์•ˆ์— ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ๋„๋ฉ”์ธ ๋ชจ๋ธ์„ ๋งŒ๋“ ๋‹ค

์žฅ์ 

  • ๋ฉ”์„œ๋“œ ์ฒด์ธ์— ๋น„ํ•ด ํ•จ์ˆ˜์˜ ์ค‘์ฒฉ ๋ฐฉ์‹์ด ๋„๋ฉ”์ธ ๊ฐ์ฒด ๊ณ„์ธต ๊ตฌ์กฐ์— ๊ทธ๋Œ€๋กœ ๋ฐ˜์˜๋จ

๋‹จ์ 

  • DSL์— ๋” ๋งŽ์€ ๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค
  • ์ธ์ˆ˜ ๋ชฉ๋ก์„ ์ •์  ๋ฉ”์„œ๋“œ์— ๋„˜๊ฒจ์ฃผ์–ด์•ผ ํ•œ๋‹ค
  • ์ธ์ˆ˜์˜ ์˜๋ฏธ๊ฐ€ ์ด๋ฆ„์ด ์•„๋‹ˆ๋ผ ์œ„์น˜์— ์˜ํ•ด ์ •์˜ ๋จ
    • ์ธ์ˆ˜์˜ ์—ญํ• ์„ ํ™•์‹คํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์—ฌ๋Ÿฌ ๋”๋ฏธ๋ฉ”์„œ๋“œ(at, on)๋ฅผ ์ด์šฉ

10.3.3 ๋žŒ๋‹ค ํ‘œํ˜„์‹์„ ์ด์šฉํ•œ ํ•จ์ˆ˜ ์‹œํ€€์‹ฑ

  • ๋žŒ๋‹ค ํ‘œํ˜„์‹์œผ๋กœ ์ •์˜ํ•œ ํ•จ์ˆ˜ ์‹œํ€€์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” DSL ํŒจํ„ด

์žฅ์ 

  • ๋ฉ”์„œ๋“œ ์ฒด์ธ ํŒจํ„ด์ฒ˜๋Ÿผ ํ”Œ๋ฃจ์–ธํŠธ ๋ฐฉ์‹์œผ๋กœ ๊ฑฐ๋ž˜ ์ฃผ๋ฌธ์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์ค‘์ฒฉ ํ•จ์ˆ˜ ํ˜•์‹ ์ฒ˜๋Ÿผ ๋‹ค์–‘ํ•œ ๋žŒ๋‹ค ํ‘œํ˜„์‹์˜ ์ค‘์ฒฉ ์ˆ˜์ค€๊ณผ ๋น„์Šทํ•˜๊ฒŒ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์œ ์ง€

๋‹จ์ 

  • ๋งŽ์€ ์„ค์ • ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ, ๋žŒ๋‹ค ํ‘œํ˜„์‹ ๋ฌธ๋ฒ•์— ์˜ํ•œ ์žก์Œ์˜ ์˜ํ–ฅ์„ ๋ฐ›์Œ๋‹ค

10.3.4 ์กฐํ•ฉํ•˜๊ธฐ

  • ์„ธ ๊ฐ€์ง€ DSL ํŒจํ„ด์„ ํ˜ผ์šฉํ•ด ๊ฐ€๋…์„ฑ ์žˆ๋Š” DSL์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ
  • ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ DSL ํŒจํ„ด์„ ๋ฐฐ์šฐ๋Š”๋ฐ ์˜ค๋žœ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฐ๋‹ค

10.3.5 DSL์— ๋ฉ”์„œ๋“œ ์ฐธ์กฐ ์‚ฌ์šฉํ•˜๊ธฐ

  • ์ฃผ๋ฌธ์˜ ์ด ํ•ฉ์— 0๊ฐœ ์ด์ƒ์˜ ์„ธ๊ธˆ์„ ์ถ”๊ฐ€ํ•ด ์ตœ์ข…๊ฐ’์„ ๊ณ„์‚ฐํ•˜๋Š” ๊ธฐ๋Šฅ ์ถ”๊ฐ€

double value = calculate(order, true, false, true);

  • ๋ถˆ๋ฆฌ์–ธ ๋ณ€์ˆ˜์˜ ์ˆœ์„œ๋ฅผ ๊ธฐ์–ตํ•˜๊ธฐ๋„ ์–ด๋ ต๊ณ  ์–ด๋–ค ์„ธ๊ธˆ์ด ์ ์šฉ๋˜์—ˆ๋Š”์ง€ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ค์›€
double value = new TaxCalculator().withTaxRegional()
                                  .withTaxSurcharge()
                                  .calculate(order);
  • ๋„๋ฉ”์ธ์˜ ๊ฐ ์„ธ๊ธˆ์— ํ•ด๋‹นํ•˜๋Š” ๋ถˆ๋ฆฌ์–ธ ํ•„๋“œ๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ ํ™•์žฅ์„ฑ์ด ์ œํ•œ์ ์ž„
  • ์ž๋ฐ”์˜ ํ•จ์ˆ˜ํ˜• ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜์—ฌ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ์œ ์—ฐํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ฆฌํŒฉํ„ฐ๋ง
double value = new TaxCalculator().with(Tax::regional)
                                  .with(Tax::surcharge)
                                  .calculate(order);

10.4 ์‹ค์ƒํ™œ์˜ ์ž๋ฐ”8 DSL

  • DSL ํŒจํ„ด์˜ ์žฅ์ ๊ณผ ๋‹จ์ 

10.4.1 jOOQ(java Object Oriented Querying)

  • SQL์„ ๊ตฌํ˜„ํ•˜๋Š” ๋‚ด๋ถ€์  DSL, ์ž๋ฐ”์— ์ง์ ‘ ๋‚ด์žฅ๋œ ํ˜•์‹ ์•ˆ์ „ ์–ธ์–ด

10.4.2 ํ์ปด๋ฒ„(Cucumber)

  • ๋™์ž‘ ์ฃผ๋„ ๊ฐœ๋ฐœ(BDD, Behavior-driven development) ํ”„๋ ˆ์ž„์›Œํฌ
  • ๊ฐœ๋ฐœ์ž๊ฐ€ ๋น„์ฆˆ๋‹ˆ์Šค ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ํ‰๋ฌธ ์˜์–ด๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” BDD ๋„๊ตฌ
  • ์ „์ œ ์กฐ๊ฑด ์ •์˜(Given), ์‹œํ—˜ํ•˜๋ ค๋Š” ๋„๋ฉ”์ธ ๊ฐ์ฒด์˜ ์‹ค์งˆ ํ˜ธ์ถœ(When), ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์˜ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•˜๋Š” assertion(Then)

10.4.3 ์Šคํ”„๋ง ํ†ตํ•ฉ

  • ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ํ†ตํ•ฉํŒจํ„ด์„ ์ง€์›ํ•  ์ˆ˜ ์žˆ๋„๋ก ์˜์กด์„ฑ ์ฃผ์ž…์— ๊ธฐ๋ฐ˜ํ•œ ์Šคํ”„๋ง ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ์„ ํ™•์žฅ
  • ์Šคํ”„๋ง ํ†ตํ•ฉ์˜ ํ•ต์‹ฌ ๋ชฉํ‘œ๋Š” ๋ณต์žกํ•œ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ํ†ตํ•ฉ ์†”๋ฃจ์…˜์„ ๊ตฌํ˜„ํ•˜๋Š” ๋‹จ์ˆœํ•œ ๋ชจ๋ธ์„ ์ œ๊ณตํ•˜๊ณ  ๋น„๋™๊ธฐ, ๋ฉ”์‹œ์ง€ ์ฃผ๋„ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‰ฝ๊ฒŒ ์ ์šฉํ•˜๋„๋ก ๋•๋Š” ๊ฒƒ

10.5 ๋งˆ์น˜๋ฉฐ

  • DSL์˜ ์ฃผ์š” ๊ธฐ๋Šฅ์€ ๊ฐœ๋ฐœ์ž์™€ ๋„๋ฉ”์ธ ์ „๋ฌธ๊ฐ€ ์‚ฌ์ด์˜ ๊ฐ„๊ฒฉ์„ ์ขํžˆ๋Š” ๊ฒƒ
  • DSL์€ ๋‚ด๋ถ€์  DSL๊ณผ ์™ธ๋ถ€์  DSL๋กœ ๋ถ„๋ฅ˜ํ•  ์ˆ˜ ์žˆ๋‹ค
  • JVM์—์„œ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์Šค์นผ๋ผ, ๊ทธ๋ฃจ๋น„ ๋“ฑ์˜ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ๋‹ค์ค‘ DSL์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์ž๋ฐ”๋Š” ์ž๋ฐ”์˜ ์žฅํ™ฉํ•จ๊ณผ ๋ฌธ๋ฒ•์  ์—„๊ฒฉํ•จ ๋•Œ๋ฌธ์— ๋‚ด๋ถ€ DSL ๊ฐœ๋ฐœ ์–ธ์–ด๋กœ ์ ํ•ฉํ•˜์ง€ ์•Š์•˜์œผ๋‚˜ ์ž๋ฐ” 8์˜ ๋žŒ๋‹ค ํ‘œํ˜„์‹๊ณผ ๋ฉ”์„œ๋“œ ์ฐธ์กฐ ๋•๋ถ„์— ์ƒํ™ฉ์ด ๋งŽ์ด ๊ฐœ์„ ๋จ
โš ๏ธ **GitHub.com Fallback** โš ๏ธ