๋ณต์žก์„ฑ์€ ์ฃฝ์Œ์ด๋‹ค. ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ƒ๊ธฐ๋ฅผ ์•—์•„๊ฐ€๋ฉฐ, ์ œํ’ˆ์„ ๊ณ„ํšํ•˜๊ณ  ์ œ์ž‘ํ•˜๊ณ  ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ ๋‹ค. - ๋ ˆ์ด ์˜ค์ง€, ๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ ์ตœ๊ณ  ๊ธฐ์ˆ  ์ฑ…์ž„์ž(CTO)

๋„์‹œ๋ฅผ ์„ธ์šด๋‹ค๋ฉด?

๋„์‹œ๊ฐ€ ๋Œ์•„๊ฐ€๋Š” ์ด์œ ๋Š”, ๊ฐ ๋ถ„์•ผ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ํŒ€์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ ์ ˆํ•œ ์ถ”์ƒํ™”์™€ ๋ชจ๋“ˆํ™” ๋•Œ๋ฌธ์ด๋‹ค.

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

์‹œ์Šคํ…œ ์ œ์ž‘๊ณผ ์‹œ์Šคํ…œ ์‚ฌ์šฉ์„ ๋ถ„๋ฆฌํ•˜๋ผ

์„ค์ • ๋…ผ๋ฆฌ๋Š” ์ผ๋ฐ˜ ์‹คํ–‰ ๋…ผ๋ฆฌ์™€ ๋ถ„๋ฆฌํ•ด์•ผ ๋ชจ๋“ˆ์„ฑ์ด ๋†’์•„์ง„๋‹ค.

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

/* Code 1-1 */
  
  public Service getService() {
      if (service == null)
          service = new MyServiceImpl(...); // ๋ชจ๋“  ์ƒํ™ฉ์— ์ ํ•ฉํ•œ ๊ฐ์ฒด์ธ๊ฐ€..?
      return service;
  }

์‹œ์ž‘ ๋‹จ๊ณ„๋Š” ๋ชจ๋“  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํ’€์–ด์•ผ ํ•  ๊ด€์‹ฌ์‚ฌ์ด๋‹ค. ์ด๋Ÿฐ ๊ด€์‹ฌ์‚ฌ๋กœ ํ‘œํ˜„๋˜๋Š” ๊ฒฝ์šฐ ์ด๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์œ„์˜ ์ฝ”๋“œ๋ฅผ ์ด๋ฅผ ๋ถ„๋ฆฌํ•˜์ง€ ์•Š์€ ์˜ˆ์‹œ์ด๋‹ค. ์ด๋Š” Lazy Initialization, Lazy Evaluation ์ด๋ผ๋Š” ๊ธฐ๋ฒ•์ด๋‹ค. ๋‹ค์Œ์˜ ์žฅ์ ์„ ๊ฐ€์ง„๋‹ค.

  1. ์‹ค์ œ๋กœ ํ•„์š”ํ•  ๋–„๊นŒ์ง€ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ถˆํ•„์š”ํ•œ ๋ถ€ํ•˜๊ฐ€ ๊ฑธ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.
  2. ๋”ฐ๋ผ์„œ ๊ทธ๋งŒํผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ๊ฐ„์ด ์งง์•„์ง„๋‹ค.
  3. ์–ด๋–ค ๊ฒฝ์šฐ์—๋„ null์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š”๋‹ค.

ํ•˜์ง€๋งŒ, ๋‹ค์Œ์˜ ๋‹จ์ ์„ ๊ฐ–๋Š”๋‹ค.

  1. getService ๋ฉ”์„œ๋“œ๊ฐ€ ํ•ด๋‹น ๊ฐ์ฒด์˜ ์‚ฌ์šฉ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด MyServiceImpl ์ƒ์„ฑ์ž ์ธ์ˆ˜์— ๋ช…์‹œ์ ์œผ๋กœ ์˜์กดํ•œ๋‹ค.
  2. MyServiceImpl ์ด ๋ฌด๊ฑฐ์šด ๊ฐ์ฒด๋ผ๋ฉด ๋‹จ์œ„ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋ ค์›Œ์ง„๋‹ค.
    • ํ…Œ์ŠคํŠธ ์ „์šฉ ๊ฐ์ฒด(Test Double, mock object)๋กœ service ๋ณ€์ˆ˜์— ํ• ๋‹นํ•ด์•ผ ํ•œ๋‹ค.
    • service๊ฐ€ null์ผ ๋•Œ์™€ ๊ทธ๋ ‡์ง€ ์•Š์„ ๋•Œ๋„ ํ…Œ์ŠคํŠธํ•ด์•ผ ํ•œ๋‹ค. ์ด๋Š” ์ƒ์„ฑ ๋กœ์ง๊ณผ ์‚ฌ์šฉ ๋กœ์ง์ด ํ˜ผ์žฌ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•œ๋‹ค.
    • ๊ฒฐ๊ณผ์ ์œผ๋กœ ์ž‘๊ฒŒ๋‚˜๋งˆ SRP์„ ์ค€์ˆ˜ํ•˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋‹ค.
  3. ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ฌธ์ œ๋Š” ์ƒ์„ฑ์‹œ MyServiceImpl์ด ๋ชจ๋“  ์ƒํ™ฉ์— ์ ํ•ฉํ•œ ๊ฐ์ฒด์ธ๊ฐ€ํ•˜๋Š” ์ ์ด๋‹ค.

์ดˆ๊ธฐํ™” ์ง€์—ฐ์„ ํ•œ ๋ฒˆ ์ •๋„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋ณ„๋กœ ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Ÿฐ ์„ค์ • ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์„ค์ • ๋กœ์ง์ด ๊ณง๊ณง์— ํฉ์–ด์ ธ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ๋ชจ๋“ˆ์„ฑ์€ ์ €์กฐํ•˜๋ฉฐ ์ค‘๋ณต์ด ์‹ฌํ•˜๋‹ค. ์„ค์ • ๋…ผ๋ฆฌ๋Š” ์ผ๋ฐ˜ ์‹คํ–‰ ๋…ผ๋ฆฌ์™€ ๋ถ„๋ฆฌํ•ด์•ผ ๋ชจ๋“ˆ์„ฑ์ด ๋†’์•„์ง„๋‹ค.

Main ๋ถ„๋ฆฌ

  1. main์ด builder์—๊ฒŒ ๊ฐ์ฒด ์ƒ์„ฑ์„ ์š”์ฒญํ•œ๋‹ค.
  2. application์€ builder๊ฐ€ ๋งŒ๋“  ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์ด๋Ÿฐ ๋ฐฉ์‹์„ ํ†ตํ•ด application์ด ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ณผ์ •์„ ์ „ํ˜€ ๋ชจ๋ฅด๋ฉด์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. application์€ ๋ชจ๋“  ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค.

ํŒฉํ† ๋ฆฌ

main ๋ถ„๋ฆฌ ์ฒ˜๋Ÿผ ์•„์˜ˆ ์‹œ์Šคํ…œ ์ดˆ๊ธฐ ์ƒ์„ฑ ์‹œ์ ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๊ฒ ์ง€๋งŒ, ๋•Œ๋–„๋กœ application์ด ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ์‹œ์ ์„ ๊ฒฐ์ •ํ•  ํ•„์š”๋„ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ฃผ๋ฌธ ์ฒ˜๋ฆฌ ์‹œ์Šคํ…œ์—์„œ application์ด LineItem ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ Order์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์žˆ๊ฒ ๋‹ค.

์ด๋Ÿฐ ๊ฒฝ์šฐ Abstract Factory ํŒจํ„ด์„ ์‚ฌ์šฉํ•œ๋‹ค. ๊ทธ๋ฆผ์„ ๋ณด๋ฉด, OrderProcessing์€ LineItemFactory Interface์— ์š”์ฒญํ•œ๋‹ค. ์‹ค์ œ ๊ตฌํ˜„์ฒด๋Š” main์ด ๋งŒ๋“  LineItemFactoryImplementation์ด๊ณ , ์ด๋…€์„์ด LineItem์„ ์ƒ์„ฑํ•œ๋‹ค.

์˜์กด์„ฑ ์ฃผ์ž…

์‚ฌ์šฉ๊ณผ ์ œ์ž‘์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ๋งค์ปค๋‹ˆ์ฆ˜ ํ•˜๋‚˜๊ฐ€ ์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection)์ด๋‹ค. DI๋Š” ์ œ์–ด ์—ญ์ „(Inversion of Control: IoC) ๊ธฐ๋ฒ•์„ ์˜์กด์„ฑ ๊ด€๋ฆฌ์— ์ ์šฉํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋‹ค.

์ œ์–ด ์—ญ์ „์—์„œ๋Š” ํ•œ ๊ฐ์ฒด๊ฐ€ ๋งก์€ ๋ณด์กฐ ์ฑ…์ž„์„ ์ƒˆ๋กœ์šด ๊ฐ์ฒด์—๊ฒŒ ์ „์ ์œผ๋กœ ๋– ๋„˜๊ธด๋‹ค. ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋Š” ๋„˜๊ฒจ๋ฐ›์€ ์ฑ…์ž„๋งŒ ๋งก๊ธฐ ๋•Œ๋ฌธ์—, SRP๋ฅผ ์ค€์ˆ˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ์ด๋Ÿฐ ์˜์กด์„ฑ ๊ด€๋ฆฌ๋ฅผ ํ•˜๋Š”๋ฐ ์žˆ์–ด, ๊ฐ์ฒด๋Š” ์˜์กด์„ฑ ์ž์ฒด๋ฅผ ์ธ์Šคํ„ด์Šค๋กœ ๋งŒ๋“œ๋Š” ์ฑ…์ž„์€ ์ง€์ง€ ์•Š๋Š”๋‹ค. ์ฆ‰, ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•˜๋Š” ์ „๋‹ด ๊ฐ์ฒด๊ฐ€ ๋”ฐ๋กœ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๋ง์ด๋‹ค. ์ด๋Ÿฐ ์ดˆ๊ธฐ ์„ค์ •์„ ์ฃผ์ž…ํ•˜๋Š” ๊ณผ์ •์€ ์‹œ์Šคํ…œ ์ „์ฒด์—์„œ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, main ๋ฃจํ‹ด์ด๋‚˜ ํŠน์ˆ˜ container(DI Container)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

/* Code 1-3 */
MyService myService = (MyService)(jndiContext.lookup(โ€œNameOfMyServiceโ€));

์œ„ ์ฝ”๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ชฝ์—์„œ๋Š” ์‹ค์ œ๋กœ lookup ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฌด์—‡์„(์–ด๋–ค ๊ตฌํ˜„์ฒด๋ฅผ) ๋ฆฌํ„ดํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ๊ด€์—ฌํ•˜์ง€ ์•Š์œผ๋ฉด์„œ ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

์ง„์ •ํ•œ ์˜์กด์„ฑ ์ฃผ์ž…์€ ์—ฌ๊ธฐ์—์„œ ํ•œ ๋‹จ๊ณ„ ๋” ๋‚˜์•„๊ฐ€ ์™„์ „ํžˆ ์ˆ˜๋™์ ์ธ ํ˜•ํƒœ๋ฅผ ์ง€๋‹Œ๋‹ค. ์˜์กด์„ฑ์„ ํ•„์š”๋กœ ํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ ์ง์ ‘ ์˜์กด์„ฑ์„ ํ•ด๊ฒฐ(์ƒ์„ฑ, ์—ฐ๊ฒฐ)ํ•˜๋Š” ๋Œ€์‹  ์ƒ์„ฑ์ž/setter ๋“ฑ์„ ํ†ตํ•ด DI ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ํ•ด๋‹น ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•˜๋„๋ก ๋„์™€์ค€๋‹ค. (๋ณดํ†ต ์šฐ๋ฆฌ๊ฐ€ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•)

ํ™•์žฅ

์ฒ˜์Œ๋ถ€ํ„ฐ ๋ฏธ๋ž˜์˜ ์š”๊ตฌ์‚ฌํ•ญ๊นŒ์ง€ ๊ณ ๋ คํ•˜์—ฌ ์‹œ์Šคํ…œ์„ ๋งŒ๋“ ๋‹ค๋Š” ๋ฏฟ์Œ์€ ๋ฏธ์‹ ์ด๋‹ค.

์šฐ๋ฆฌ๋Š” ์˜ค๋Š˜ ์ฃผ์–ด์ง„ ์‚ฌ์šฉ์ž ์Šคํ† ๋ฆฌ์— ๋งž์ถฐ ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๋‚ด์ผ์€ ๋‚ด์ผ์˜ ์Šคํ† ๋ฆฌ์— ๋งž์ถฐ ์‹œ์Šคํ…œ์„ ์กฐ์ •ํ•˜๊ณ  ํ™•์žฅํ•œ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ˜๋ณต์ ์ด๊ณ  ์ ์ง„์ ์ธ Agile ๋ฐฉ์‹์ด๋‹ค. TDD, Refactoring์œผ๋กœ ์ด์–ด์ง€๋Š” ๊นจ๊ธ‹ํ•œ ์ฝ”๋“œ๋Š” ์ฝ”๋“œ ์ˆ˜์ค€์—์„œ ์‹œ์Šคํ…œ์„ ์กฐ์ •ํ•˜๊ณ  ํ™•์žฅํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ ๋‹ค.

์‹œ์Šคํ…œ ์ˆ˜์ค€์—์„œ๋Š” ์–ด๋–จ๊นŒ? ์–ด๋–ค์‹์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์‹œ์Šคํ…œ ์ „๋ฐ˜์—์„œ ์ด๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์ข‹๊ฒŒ ํ•  ์ˆ˜ ์žˆ์„๊นŒ? ๋‹ต๋ถ€ํ„ฐ ๋งํ•˜์ž๋ฉด, ๊ด€์‹ฌ์‚ฌ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‚˜๋ˆ„์–ด์•ผ ํ•œ๋‹ค.

๋จผ์ €, ์Šค์ผ€์ผ๋ง์„ ๊ณ ๋ คํ•˜์ง€ ์•Š์€ ๊ตฌ์กฐ์— ๋Œ€ํ•ด EJB1/EJB2๋ฅผ ์˜ˆ์‹œ๋กœ ์•Œ์•„๋ณด์ž.

  • EJB์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋ณธ ์ฑ•ํ„ฐ์™€ ๊ด€๊ณ„๊ฐ€ ์—†์œผ๋ฏ€๋กœ ์ƒ๋žตํ•œ๋‹ค. (EJB์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๊ฐœ์š”๋Š” ๊ฐ์ฃผ๋กœ ์ถ”๊ฐ€ ๋ฐ”๋žŒ)
  • ์šฐ์„  entity bean์ด๋ž€ ๊ด€๊ณ„ ๋ฐ์ดํ„ฐ(DB ํ…Œ์ด๋ธ”์˜ ํ–‰)์˜ ๋ฉ”๋ชจ๋ฆฌ์ƒ์˜ ํ‘œํ˜„์ด๋ผ๋Š” ๊ฒƒ๋งŒ ์•Œ๊ณ  ๊ฐ€์ž. (An entity bean is an in-memory representation of relational data, in other words, a table row.)
/* Code 2-1(Listing 11-1): An EJB2 local interface for a Bank EJB */
 
package com.example.banking;
import java.util.Collections;
import javax.ejb.*;
 
public interface BankLocal extends java.ejb.EJBLocalObject {
    String getStreetAddr1() throws EJBException;
    String getStreetAddr2() throws EJBException;
    String getCity() throws EJBException;
    String getState() throws EJBException;
    String getZipCode() throws EJBException;
    void setStreetAddr1(String street1) throws EJBException;
    void setStreetAddr2(String street2) throws EJBException;
    void setCity(String city) throws EJBException;
    void setState(String state) throws EJBException;
    void setZipCode(String zip) throws EJBException;
    Collection getAccounts() throws EJBException;
    void setAccounts(Collection accounts) throws EJBException;
    void addAccount(AccountDTO accountDTO) throws EJBException;
}
/* Code 2-2(Listing 11-2): The corresponding EJB2 Entity Bean Implementation */
 
package com.example.banking;
import java.util.Collections;
import javax.ejb.*;
 
public abstract class Bank implements javax.ejb.EntityBean {
    // Business logic...
    public abstract String getStreetAddr1();
    public abstract String getStreetAddr2();
    public abstract String getCity();
    public abstract String getState();
    public abstract String getZipCode();
    public abstract void setStreetAddr1(String street1);
    public abstract void setStreetAddr2(String street2);
    public abstract void setCity(String city);
    public abstract void setState(String state);
    public abstract void setZipCode(String zip);
    public abstract Collection getAccounts();
    public abstract void setAccounts(Collection accounts);
    
    public void addAccount(AccountDTO accountDTO) {
        InitialContext context = new InitialContext();
        AccountHomeLocal accountHome = context.lookup("AccountHomeLocal");
        AccountLocal account = accountHome.create(accountDTO);
        Collection accounts = getAccounts();
        accounts.add(account);
    }
    
    // EJB ์ปจํ…Œ์ด๋„ˆ ๋…ผ๋ฆฌ
    public abstract void setId(Integer id);
    public abstract Integer getId();
    public Integer ejbCreate(Integer id) { ... }
    public void ejbPostCreate(Integer id) { ... }
    
    // ๋‚˜๋จธ์ง€๋„ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ ๋น„์–ด์žˆ๋‹ค.
    public void setEntityContext(EntityContext ctx) {}
    public void unsetEntityContext() {}
    public void ejbActivate() {}
    public void ejbPassivate() {}
    public void ejbLoad() {}
    public void ejbStore() {}
    public void ejbRemove() {}
}

์œ„ ์ฝ”๋“œ์™€ ๊ฐ™์€ ์ „ํ˜•์ ์ธ EJB2 ๊ฐ์ฒด ๊ตฌ์กฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ์ œ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

  1. ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์ด EJB2 ์ปจํ…Œ์ด๋„ˆ์— ํƒ€์ดํŠธํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค. Entity๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ปจํ…Œ์ด๋„ˆ ํƒ€์ž…์„ subclassํ•˜๊ณ  ํ•„์š”ํ•œ lifecycle ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.
  2. ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋˜์ง€ ์•Š์„ ํ…Œ์ŠคํŠธ ๊ฐ์ฒด์˜ ์ž‘์„ฑ์„ ์œ„ํ•ด mock ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ์—๋„ ๋ฌด์˜๋ฏธํ•œ ๋…ธ๋ ฅ์ด ๋งŽ์ด ๋“ ๋‹ค. EJB2 ๊ตฌ์กฐ๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ๊ตฌ์กฐ์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.
  3. OOP ๋˜ํ•œ ๋“ฑํ•œ์‹œ๋˜๊ณ  ์žˆ๋‹ค. ์ƒ์†๋„ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉฐ ์“ธ๋ฐ์—†๋Š” DTO(Data Transfer Object)๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.

(์ด ๋ถ€๋ถ„ ์ž˜ ์ดํ•ดํ•˜์ง€ ๋ชปํ–ˆ๋‹ค..)

ํšก๋‹จ(cross-cutting) ๊ด€์‹ฌ์‚ฌ

์ด๋ก ์ ์œผ๋กœ๋Š” ๋…๋ฆฝ๋œ ํ˜•ํƒœ๋กœ ๊ตฌ๋ถ„๋  ์ˆ˜ ์žˆ์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์ฝ”๋“œ์— ์‚ฐ์žฌํ•˜๊ธฐ ์‰ฌ์šด ๋ถ€๋ถ„๋“ค

ํŠธ๋žœ์žญ์…˜, ๋ณด์•ˆ, ์˜์†์„ฑ, ๋กœ๊น…, ๋กœ๊ทธ์ธ ๋ชจ๋“ˆ ๋“ฑ์€ application์˜ ๊ฐ์ฒด ๊ฒฝ๊ณ„๋ฅผ ๋„˜๋‚˜๋“œ๋Š” ๊ฒฝํ–ฅ์ด ์žˆ๋‹ค. ๋ชจ๋“  ๊ฐ์ฒด๊ฐ€ ์ „๋ฐ˜์ ์œผ๋กœ ๋™์ผํ•œ ๋ฐฉ์‹์„ ์ด์šฉํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ฐ™์€ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์—ฌ๊ธฐ์ €๊ธฐ ํฉ์–ด์ง€๊ฒŒ ๋œ๋‹ค. ์ด๋Š” Aspect-Oriented Programming(AOP)๊ณผ ๊ฐ™์€ ๋งฅ๋ฝ์ด๋ผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ž๋ฐ” ํ”„๋ก์‹œ

๊ฐ„๋‹จํ•œ ๊ฒฝ์šฐ๋ผ๋ฉด ์ž๋ฐ” ํ”„๋ก์‹œ๊ฐ€ ์ ์ ˆํ•œ ์†”๋ฃจ์…˜์ผ ๊ฒƒ์ด๋‹ค. ์•„๋ž˜๋Š” ์ž๋ฐ” ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ์ฒด์˜ ๋ณ€๊ฒฝ์ด ์ž๋™์œผ๋กœ persistant framework์— ์ €์žฅ๋˜๋Š” ๊ตฌ์กฐ์— ๋Œ€ํ•œ ์˜ˆ์‹œ์ด๋‹ค.

/* Code 3-1(Listing 11-3): JDK Proxy Example */
 
// Bank.java (suppressing package names...)
import java.utils.*;
 
// The abstraction of a bank.
public interface Bank {
    Collection<Account> getAccounts();
    void setAccounts(Collection<Account> accounts);
}
 
// BankImpl.java
import java.utils.*;
 
// The โ€œPlain Old Java Objectโ€ (POJO) implementing the abstraction.
public class BankImpl implements Bank {
    private List<Account> accounts;
 
    public Collection<Account> getAccounts() {
        return accounts;
    }
    
    public void setAccounts(Collection<Account> accounts) {
        this.accounts = new ArrayList<Account>();
        for (Account account: accounts) {
            this.accounts.add(account);
        }
    }
}
// BankProxyHandler.java
import java.lang.reflect.*;
import java.util.*;
 
// โ€œInvocationHandlerโ€ required by the proxy API.
public class BankProxyHandler implements InvocationHandler {
    private Bank bank;
    
    public BankHandler (Bank bank) {
        this.bank = bank;
    }
    
    // Method defined in InvocationHandler
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        if (methodName.equals("getAccounts")) {
            bank.setAccounts(getAccountsFromDatabase());
            
            return bank.getAccounts();
        } else if (methodName.equals("setAccounts")) {
            bank.setAccounts((Collection<Account>) args[0]);
            setAccountsToDatabase(bank.getAccounts());
            
            return null;
        } else {
            ...
        }
    }
    
    // Lots of details here:
    protected Collection<Account> getAccountsFromDatabase() { ... }
    protected void setAccountsToDatabase(Collection<Account> accounts) { ... }
}
 
// Somewhere else...
Bank bank = (Bank) Proxy.newProxyInstance(
    Bank.class.getClassLoader(),
    new Class[] { Bank.class },
    new BankProxyHandler(new BankImpl())
);

์œ„ ์ฝ”๋“œ์— ๋Œ€ํ•œ ๊ฐ„๋žตํ•œ ์„ค๋ช…์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  1. Java Proxy API๋ฅผ ์œ„ํ•œ Bank ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.
  2. ์œ„์—์„œ ์ž‘์„ฑํ•œ Bank ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•œ BankImpl(POJO aka Plane Old Java Object)๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ์ˆœ์ˆ˜ํ•œ ๋ฐ์ดํ„ฐ๋งŒ ๋“ค์–ด๊ฐ€๋ฉฐ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์€ ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค.(๋ชจ๋ธ๊ณผ ๋กœ์ง์˜ ๋ถ„๋ฆฌ)
  3. InvocationHandler๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” BankProxyHandler๋ฅผ ์ž‘์„ฑํ•œ๋‹ค. ์ด ํ•ธ๋“ค๋Ÿฌ๋Š” Java Reflection API๋ฅผ ์ด์šฉํ•ด Bank ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฐ์ฒด๋“ค์˜ ๋ฉ”์„œ๋“œ์ฝœ์„ ๊ฐ€๋กœ์ฑŒ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ถ”๊ฐ€์ ์ธ ๋กœ์ง์„ ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ณธ ์˜ˆ์ œ์—์„œ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง(persistant stack logic)์€ ์ด ๊ณณ์— ๋“ค์–ด๊ฐ„๋‹ค.
  4. ๋งˆ์ง€๋ง‰์œผ๋กœ ์ฝ”๋“œ์˜ ๋งˆ์ง€๋ง‰ ๋ธ”๋Ÿญ๊ณผ ๊ฐ™์ด BankImpl ๊ฐ์ฒด๋ฅผ BankProxyHandler์— ํ• ๋‹น, Bank ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด ํ”„๋ก์‹œ๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด ๋ชจ๋ธ๊ณผ ๋กœ์ง์ด ๋ถ„๋ฆฌ๋œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋กœ์จ ๋ชจ๋ธ๊ณผ ๋กœ์ง์˜ ๋ถ„๋ฆฌ๋ฅผ ์ด๋ค„๋‚ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์œ„์™€ ๊ฐ™์€ ์ƒ๋Œ€์ ์œผ๋กœ ๊ฐ„๋‹จํ•œ ๊ฒฝ์šฐ์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๊ฒฐ๊ณผ์ ์œผ๋กœ ์ถ”๊ฐ€์ ์ธ ๋ณต์žกํ•œ ์ฝ”๋“œ๊ฐ€ ์ƒ๊ฒผ๋‹ค. ๋˜ ์‹œ์Šคํ…œ ๋‹จ์œ„๋กœ ์‹คํ–‰ โ€œ์ง€์ โ€์„ ๋ช…์‹œํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜๋„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ˆœ์ˆ˜ ์ž๋ฐ” AOP ํ”„๋ ˆ์ž„์›Œํฌ

์œ„ Java Proxy API์˜ ๋‹จ์ ๋“ค์€ Spring, JBoss์™€ ๊ฐ™์€ ์ˆœ์ˆ˜ ์ž๋ฐ” AOP ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ํ†ตํ•ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Spring์—์„œ๋Š” ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์„ POJO๋กœ ์ž‘์„ฑํ•ด ์ž์‹ ์ด ์†ํ•œ ๋„๋ฉ”์ธ์— ์ง‘์ค‘ํ•˜๊ฒŒ ํ•œ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ์˜์กด์„ฑ์€ ์ค„์–ด๋“ค๊ณ  ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์— ํ•„์š”ํ•œ ๊ณ ๋ฏผ๋„ ์ค„์–ด๋“ ๋‹ค. ์ด๋Ÿฌํ•œ ์‹ฌํ”Œํ•จ์€ user story์˜ ๊ตฌํ˜„๊ณผ ์œ ์ง€๋ณด์ˆ˜, ํ™•์žฅ ๋˜ํ•œ ๊ฐ„ํŽธํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ค€๋‹ค.

์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด Spring ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋™์ž‘ ๋ฐฉ์‹์— ๋Œ€ํ•ด ํ™•์ธํ•ด ๋ณด์ž.

/* Code 3-2(Listing 11-4): Spring 2.X configuration file */
 
<beans>
    ...
    <bean id="appDataSource"
        class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close"
        p:driverClassName="com.mysql.jdbc.Driver"
        p:url="jdbc:mysql://localhost:3306/mydb"
        p:username="me"/>
    
    <bean id="bankDataAccessObject"
        class="com.example.banking.persistence.BankDataAccessObject"
        p:dataSource-ref="appDataSource"/>
    
    <bean id="bank"
        class="com.example.banking.model.Bank"
        p:dataAccessObject-ref="bankDataAccessObject"/>
    ...
</beans>

Bank๊ฐ์ฒด๋Š” BankDataAccessObject๊ฐ€, BankDataAccessObject๋Š” BankDataSource๊ฐ€ ๊ฐ์‹ธ ํ”„๋ก์‹œํ•˜๋Š” ๊ตฌ์กฐ๋กœ ๋˜์–ด ๊ฐ๊ฐ์˜ bean๋“ค์ด โ€œ๋Ÿฌ์‹œ์•ˆ ์ธํ˜•โ€์˜ ํ•œ ๋ถ€๋ถ„์ฒ˜๋Ÿผ ๊ตฌ์„ฑ๋˜์—ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋Š” Bank์— ์ ‘๊ทผํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์‚ฌ์‹ค์€ ๊ฐ€์žฅ ๋ฐ”๊นฅ์˜ BankDataSource์— ์ ‘๊ทผํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

/* Code 3-3: Code 3-2์˜ ํ™œ์šฉ๋ฒ• */
 
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("app.xml", getClass()));
Bank bank = (Bank) bf.getBean("bank");

์œ„์™€ ๊ฐ™์ด ์ตœ์†Œํ•œ์˜ Spring-specificํ•œ ์ฝ”๋“œ๋งŒ ์ž‘์„ฑํ•˜๋ฉด ๋˜๋ฏ€๋กœ ํ”„๋ ˆ์ž„์›Œํฌ์™€ โ€œ๊ฑฐ์˜โ€ decouple๋œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ตฌ์กฐ ์ •์˜๋ฅผ ์œ„ํ•œ xml์€ ๋‹ค์†Œ ์žฅํ™ฉํ•˜๊ณ  ์ฝ๊ธฐ ํž˜๋“ค ์ˆ˜๋Š” ์žˆ์ง€๋งŒ Java Proxy๋ณด๋‹ค๋Š” ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•˜๋‹ค. ์ด ๊ฐœ๋…์€ ์•„๋ž˜์— ์„ค๋ช…ํ•  EJB3์˜ ๊ตฌ์กฐ ๊ฐœํŽธ์— ํฐ ์˜ํ–ฅ์„ ๋ฏธ์ณค๋‹ค. EJB3์€ xml์™€ Java annotation์„ ์‚ฌ์šฉํ•ด cross-cutting concerns๋ฅผ ์ •์˜ํ•˜๊ณ  ์„œํฌํŠธํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

/* Code 3-4(Listing 11-5): An EBJ3 Bank EJB */
 
package com.example.banking.model;
 
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collection;
 
@Entity
@Table(name = "BANKS")
public class Bank implements java.io.Serializable {
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;
    
    @Embeddable // An object โ€œinlinedโ€ in Bankโ€™s DB row
    public class Address {
        protected String streetAddr1;
        protected String streetAddr2;
        protected String city;
        protected String state;
        protected String zipCode;
    }
    
    @Embedded
    private Address address;
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy="bank")
    private Collection<Account> accounts = new ArrayList<Account>();
    public int getId() {
        return id;
    }
    
    public void setId(int id) {
        this.id = id;
    }
    
    public void addAccount(Account account) {
        account.setBank(this);
        accounts.add(account);
    }
    
    public Collection<Account> getAccounts() {
        return accounts;
    }
    
    public void setAccounts(Collection<Account> accounts) {
        this.accounts = accounts;
    }
}

์œ„์™€ ๊ฐ™์ด EJB3์€ EJB2 ๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•œ ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค. ๋ช‡๋ช‡ ์„ธ๋ถ€ ์†์„ฑ๋“ค์€ annotation์œผ๋กœ ํด๋ž˜์Šค ๋‚ด์— ์ •์˜๋˜์–ด ์žˆ์ง€๋งŒ annotation์„ ๋ฒ—์–ด๋‚˜์ง„ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด์ „๋ณด๋‹ค ๋” ๊นจ๋—ํ•˜๊ณ  ๋ช…๋ฃŒํ•œ ์ฝ”๋“œ๋ฅผ ์‚ฐ์ถœํ•˜๋ฉฐ ๊ทธ๋กœ ์ธํ•ด ์œ ์ง€๋ณด์ˆ˜, ํ…Œ์ŠคํŠธํ•˜๊ธฐ ํŽธํ•œ ์žฅ์ ์„ ๊ฐ–๊ฒŒ ๋˜์—ˆ๋‹ค.

AspectJ ๊ด€์ 

AspectJ๋Š” AOP๋ฅผ ์‹คํ˜„ํ•˜๊ธฐ ์œ„ํ•œ full-featured tool์ด๋ผ ์ผ์ปฌ์–ด์ง„๋‹ค. 8~90%์˜ ๊ฒฝ์šฐ์—๋Š” Spring AOP์™€ JBoss AOP๋กœ๋„ ์ถฉ๋ถ„ํ•˜์ง€๋งŒ AspectJ๋Š” ํ›จ์”ฌ ๊ฐ•๋ ฅํ•œ ์ˆ˜์ค€์˜ AOP๋ฅผ ์ง€์›ํ•œ๋‹ค. ๋‹ค๋งŒ ์ด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ƒˆ๋กœ์šด ํˆด, ์–ธ์–ด ๊ตฌ์กฐ, ๊ด€์Šต์ ์ธ ์ฝ”๋“œ๋ฅผ ์ตํ˜€์•ผ ํ•œ๋‹ค๋Š” ๋‹จ์ ๋„ ์กด์žฌํ•œ๋‹ค.(์ตœ๊ทผ ์†Œ๊ฐœ๋œ โ€œannotation-form AspectJโ€๋กœ ์ธํ•ด ์ ์šฉ์— ํ•„์š”ํ•œ ๋…ธ๋ ฅ์€ ๋งŽ์ด ์ค„์–ด๋“ค์—ˆ๋‹ค๊ณ  ํ•œ๋‹ค.) AOP์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ [AspectJ], [Colyer], [Spring]๋ฅผ ์ฐธ์กฐํ•˜๊ธฐ ๋ฐ”๋ž€๋‹ค.

ํ…Œ์ŠคํŠธ ์ฃผ๋„ ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ ๊ตฌ์ถ•

BDUF(Big Design Up Front: ์•ž์œผ๋กœ ๋ฒŒ์–ด์งˆ ๋ชจ๋“  ์‚ฌํ•ญ์„ ์„ค๊ณ„ํ•˜๋Š” ๊ธฐ๋ฒ•)์€ ํ•ด๋กญ๋‹ค. ์ฒ˜์Œ์— ์Ÿ์•„ ๋ถ€์€ ๋…ธ๋ ฅ์„ ๋ฒ„๋ฆฌ์ง€ ์•Š์œผ๋ ค๋Š” ์‹ฌ๋ฆฌ์  ์ €ํ•ญ, ๊ทธ๋ฆฌ๊ณ  ์ฒ˜์Œ ์„ ํƒํ•œ ์•„ํ‚คํ…์ฒ˜๊ฐ€ ํ–ฅํ›„ ์‚ฌ๊ณ  ๋ฐฉ์‹์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์œผ๋กœ ๋ณ€๊ฒฝ์„ ์‰ฝ์‚ฌ๋ฆฌ ์ˆ˜์šฉํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋œ๋‹ค.

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

์ด์ƒ์ ์ธ ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ณ๋Š” ๊ฐ๊ฐ POJO๋กœ ๋งŒ๋“ค์–ด์ง„ ๋ชจ๋“ˆํ™”๋œ ๊ด€์‹ฌ ๋ถ„์•ผ ์˜์—ญ(modularized domains of concern)์œผ๋กœ ์ด๋ฃจ์–ด์ ธ์•ผ ํ•œ๋‹ค. ๋‹ค๋ฅธ ์˜์—ญ๋ผ๋ฆฌ๋Š” Aspect์˜ ๊ฐœ๋…์„ ์‚ฌ์šฉํ•ด ์ตœ์†Œํ•œ์˜ ๊ฐ„์„ญ์œผ๋กœ ํ†ตํ•ฉ๋˜์–ด์•ผ ํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ์•„ํ‚คํ…์ณ๋Š” ์ฝ”๋“œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ test-driven๋  ์ˆ˜ ์žˆ๋‹ค.

์˜์‚ฌ ๊ฒฐ์ •์„ ์ตœ์ ํ™”ํ•˜๋ผ

๋ชจ๋“ˆ์„ ๋‚˜๋ˆ„๊ณ  ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ถ„๋ฆฌํ•˜๋ฉด ์ง€์—ฝ์ ์ธ ๊ด€๋ฆฌ์™€ ๊ฒฐ์ •์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค. ๋•Œ๋•Œ๋กœ ๊ฐ€๋Šฅํ•œ ๋งˆ์ง€๋ง‰ ์ˆœ๊ฐ„๊นŒ์ง€ ๊ฒฐ์ •์„ ๋ฏธ๋ฃจ๋Š” ๋ฐฉ๋ฒ•์ด ์ตœ์„ ์ด๋ผ๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋ง์ž.

๋ชจ๋“ˆํ™”๋œ ๊ด€์‹ฌ ๋ถ„์•ผ๋กœ ์ด๋ฃจ์–ด์ง„ POJO ์‹œ์Šคํ…œ์˜ (๋ณ€ํ™”์— ๋Œ€ํ•œ)๋ฏผ์ฒฉํ•จ์€ ๊ฐ€์žฅ ์ตœ์‹ ์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์ ์‹œ์— ์ตœ์ ์˜ ์„ ํƒ์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ค€๋‹ค. ๊ฒฐ์ •์— ํ•„์š”ํ•œ ๋ณต์žก๋„ ๋˜ํ•œ ๊ฒฝ๊ฐ๋œ๋‹ค.

๋ช…๋ฐฑํ•œ ๊ฐ€์น˜๊ฐ€ ์žˆ์„ ๋•Œ ํ‘œ์ค€์„ ํ˜„๋ช…ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋ผ

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

ํ‘œ์ค€์€ ์•„์ด๋””์–ด์™€ ์ปดํฌ๋„ŒํŠธ์˜ ์žฌ์‚ฌ์šฉ, ๊ด€๋ จ ์ „๋ฌธ๊ฐ€ ์ฑ„์šฉ, ์ข‹์€ ์•„์ด๋””์–ด์˜ ์บก์Šํ™”, ์ปดํฌ๋„ŒํŠธ๋“ค์˜ ์—ฐ๊ฒฐ์„ ์‰ฝ๊ฒŒ ๋„์™€ ์ค€๋‹ค. ํ•˜์ง€๋งŒ ์ข…์ข… ํ‘œ์ค€์„ ๋งŒ๋“œ๋Š” ๋ฐ์— ๋“œ๋Š” ์‹œ๊ฐ„์€ ๋‚ฉํ’ˆ ๊ธฐํ•œ์„ ๋งž์ถ”๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค๊ณ , ํ˜น์€ ์ตœ์ดˆ์— ์ œ๊ณตํ•˜๋ ค๋˜ ๊ธฐ๋Šฅ๊ณผ ๋™๋–จ์–ด์ง€๊ฒŒ ๋˜๊ธฐ๋„ ํ•œ๋‹ค.

์‹œ์Šคํ…œ์€ ๋„๋ฉ”์ธ ํŠนํ™” ์–ธ์–ด๊ฐ€ ํ•„์š”ํ•˜๋‹ค

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

DSL์€ โ€œ๋ชจ๋“  ๋‹จ๊ณ„์—์„œ์˜ ์ถ”์ƒํ™”โ€์™€ โ€œ๋ชจ๋“  ๋„๋ฉ”์ธ์˜ POJOํ™”โ€๋ฅผ ๊ณ ์ฐจ์›์  ๊ทœ์น™๊ณผ ์ €์ฐจ์›์  ๋””ํ…Œ์ผ ์ „๋ฐ˜์— ๊ฑธ์ณ ๋„์™€ ์ค€๋‹ค.

๊ฒฐ๋ก 

์‹œ์Šคํ…œ ์—ญ์‹œ ๊นจ๋—ํ•ด์•ผ ํ•œ๋‹ค.

์นจ๋žต์ ์ธ(invasive) ์•„ํ‚คํ…์ณ๋Š” ๋„๋ฉ”์ธ ๋กœ์ง์— ํ”ผํ•ด๋ฅผ ์ฃผ๊ณ  ์‹ ์†์„ฑ์—๋„ ์˜ํ–ฅ์„ ์ค€๋‹ค. ๋„๋ฉ”์ธ ๋กœ์ง์ด ๋ชจํ˜ธํ•ด์ง€๋ฉด ๋ฒ„๊ทธ๋Š” ์ˆจ๊ธฐ ์‰ฌ์›Œ์ง€๊ณ  ๊ธฐ๋Šฅ ๊ตฌํ˜„์€ ์–ด๋ ค์›Œ ์ง„๋‹ค. ์‹ ์†์„ฑ์ด ์นจํ•ด๋˜๋ฉด ์ƒ์‚ฐ์„ฑ์ด ์ €ํ•ด๋˜๊ณ  TDD๋กœ ์ธํ•œ ์ด๋“ ๋˜ํ•œ ์–ป์„ ์ˆ˜ ์—†๋‹ค. ์˜๋„๋Š” ๋ชจ๋“  ๋ ˆ๋ฒจ์˜ ์ถ”์ƒํ™”์—์„œ ๋ช…ํ™•ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋Š” ๊ฐ๊ฐ์˜ concern๋“ค์„ POJO๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ์™€ aspect-like ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ํ†ตํ•ด ๊ตฌ์„ฑํ•  ๋•Œ ๋น„๋กœ์†Œ ์‹คํ˜„๋  ์ˆ˜ ์žˆ๋‹ค. ๋‹น์‹ ์ด ์‹œ์Šคํ…œ์„ ๋””์ž์ธํ•˜๋“  ๋…์ž์ ์ธ ๋ชจ๋“ˆ์„ ๋””์ž์ธํ•˜๋“ , ๋™์ž‘ํ•˜๋Š” ๋ฒ”์œ„์—์„œ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

Reference