/images/profile.png

๊ทธ๋Ÿฐ ๊ฐœ๋ฐœ์ž๋กœ ๊ดœ์ฐฎ์€๊ฐ€ - '์ž๊ธฐ๊ณ„๋ฐœ' ํŽธ

ใ€€ํ•™์ฐฝ ์‹œ์ ˆ์—” ‘์„ ์ƒ๋‹˜’๊ป˜์„œ ์ •ํ•ด๋†“์œผ์‹  ์ปค๋ฆฌํ˜๋Ÿผ์— ๋”ฐ๋ผ๊ฐ€๊ธฐ๋งŒ ํ•˜๋ฉด ํฐ ๋ฌธ์ œ ์—†์ด ์ง€์‹์„ ํ•™์Šตํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ๊ฑฐ๊ธฐ์— ์ฃผ๊ธฐ์ ์œผ๋กœ ์น˜๋ฅด๋Š” ์‹œํ—˜์„ ํ†ตํ•ด ‘์ ์ˆ˜’๋ผ๋Š” ํ‰๊ฐ€ ๊ธฐ์ค€์œผ๋กœ ์–ผ๋งˆ๋‚˜ ์ž˜ ์„ฑ์žฅํ–ˆ๋‚˜๋ฅผ ๊ฒ€์‚ฌํ•˜๊ธฐ๋„ ํ•œ๋‹ค. ์กธ์—… ํ›„ ์–ด๋ ต๊ฒŒ ์–ด๋ ต๊ฒŒ ์ทจ์—…์— ์„ฑ๊ณต์„ ํ•˜์—ฌ ‘์‹ ์ž… ๊ฐœ๋ฐœ์ž’๋ผ๋Š” ๋ฐฐ์ง€๋ฅผ ๋‹ฌ๊ณ  ํšŒ์‚ฌ์— ์ฒซ ์ถœ๊ทผ. ๊ทธ๋ ‡๊ฒŒ n ๋…„์ด ์ง€๋‚œ ์ง€๊ธˆ๊ณผ ๋ผ๋–ผ ์‹œ์ ˆ(?)์„ ๋น„๊ตํ•ด ๋ณด๋ฉฐ ๊ณผ์—ฐ ‘ํ•™์Šต’์— ๋Œ€ํ•œ ์—ด์ • ๊ทธ๋ž˜ํ”„๊ฐ€ ์•„์ง๋„ ์šฐ์ƒํ–ฅ ์ค‘์ธ๊ฐ€? ํ•˜๋Š” ์งˆ๋ฌธ์—” ์ผ๋‹จ ๋‹จ์ „๋ถ€ํ„ฐ ์˜ฌ๋ผ์˜ค๋Š” ๊นŠ์€ ํ•œ์ˆจ๊ณผ ํ•จ๊ฒŒ ์ด์ƒํ•˜๊ฒŒ๋„ ์•ž์ด ์บ„์บ„ํ•ด์ง„๋‹ค.

/images/a-good-developer-in-terms-of-self-development/latte.jpg
์šฐ๋ฆฌ๋Š” ๋ชจ๋‘ ๋ผ๋–ผ ์‹œ์ ˆ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
์ถœ์ฒ˜ : https://www.dogdrip.net/212294087

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

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

๋ธ”๋กœ๊ทธ

ใ€€๊ฐœ๋ฐœ์ž๊ฐ€ ๊ธ€๋„ ์จ์•ผ ํ•˜๋‚˜?๋ผ๋Š” ์งˆ๋ฌธ์—๋Š” ํ•„์ž๊ฐ€ ์˜ˆ์ „์— ์ •๋ฆฌํ•ด๋‘” ๊ฐœ๋ฐœํ•˜๊ธฐ ๋ฐ”์œ๋ฐ ๊ธ€๊นŒ์ง€ ์“ฐ๋ผ๊ณ ? (๊ธ€์“ฐ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์ž.)๋ผ๋Š” ๊ธ€์„ ์ฐธ๊ณ ํ•ด๋ด๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค. ํ•ด๋‹น ํฌ์ŠคํŒ…์—์„œ ์ˆ˜์ฐจ๋ก€ ๊ฐ•์กฐํ•˜์˜€์ง€๋งŒ ๊ทธ๋งŒํผ ๊ฐœ๋ฐœ์ž์—๊ฒŒ๋Š” ํŠนํžˆ๋‚˜ ๊ธ€์“ฐ๊ธฐ๊ฐ€ ์ค‘์š”ํ•˜๊ณ  ํ•„์š”ํ•˜๋‹ค. ๊ธ€์„ ๊ผญ ‘์ž˜’์จ์•ผ ํ•œ๋‹ค๋Š” ๋ถ€๋‹ด์„ ๊ฐ€์งˆ ํ•„์š”๋Š” ์—†๋‹ค. (ํ•„์ž๋„ ๊ทธ๋ ‡๊ฒŒ ์ž˜ ์“ฐ๋Š” ํŽธ์€ ์•„๋‹ˆ๋‹ค…) ๋‹ค๋งŒ ๋ฌด์–ธ๊ฐ€๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ์ •๋ฆฌํ•˜๊ณ  ์ž์‹ ๋งŒ์˜ ๊ธฐ์ค€์— ๋งž์ถ”์–ด ์žฌ ์ •๋ฆฌํ•˜๋Š” ์Šต๊ด€์„ ๊ธฐ๋ฅด๋‹ค ๋ณด๋ฉด ์ด๋Ÿฌํ•œ ์ƒ๊ฐ๋“ค์ด ๊ฐœ๋ฐœ์„ ํ•  ๋•Œ์—๋„ ๋„์›€์ด ์ƒ๋‹นํžˆ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

/images/a-good-developer-in-terms-of-self-development/exception.gif
๊ฐœ๋ฐœ์„ ํ•˜๋‹ค๋ณด๋ฉด ๊ผผ๊ผผํ•˜๊ฒŒ ์ฒดํฌํ•ด์•ผํ•  ์˜ˆ์™ธ๊ฐ€ ๋„ˆ๋ฌด ๋งŽ๋‹ค.
์ถœ์ฒ˜ : https://gfycat.com/ko/menacingeducatedatlasmoth

ใ€€๋ณต์žกํ•œ ๊ตฌ์กฐ๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” ๊ฐœ๋ฐœ์„ ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. ์—ฐ๋™ํ•˜๋Š” ์‹œ์Šคํ…œ๋„ ๋งŽ๊ณ  ์ •๋ง ๋‹ค์–‘ํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์„ ํ•˜๋‚˜์˜ ์‹œ์Šคํ…œ์—์„œ ๊ตฌํ˜„์„ ํ•ด์•ผ ํ•  ๊ฒฝ์šฐ ๋ณดํ†ต ๊ฐœ๋ฐœ์„ ํ•˜๊ธฐ์— ์•ž์„œ ‘์„ค๊ณ„’๋ผ๋Š” ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์น˜๊ธฐ ๋งˆ๋ จ์ด๋‹ค. ๊ทธ๋•Œ ๊ธ€์“ฐ๊ธฐ๋ฅผ ํ–ˆ์„ ๋•Œ์˜ ์Šต๊ด€(์Šคํ‚ฌ?)์„ ์ ์šฉํ•ด ๋ณด๋ฉด ์š”๊ตฌ ์‚ฌํ•ญ๋“ค ์ค‘์— ์ค‘์š”ํ•œ feature ๊ธฐ์ค€์œผ๋กœ ์ •๋ฆฌ๋ฅผ ํ•˜๊ฒŒ ๋˜๊ณ , ๊ฐ ์ดํ•ด๊ด€๊ณ„์ž๋“ค์—๊ฒŒ ์ •๋ฆฌํ•œ ๋ถ€๋ถ„์„ ๊ณต์œ ํ•˜๋ฉฐ ์˜ˆ์™ธ ์ƒํ™ฉ์„ ๋ณด๋‹ค ๋น ๋ฅด๊ฒŒ ํ™•์ธํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์‹ฌ์ง€์–ด ์ฝ”๋“œ ๋ ˆ๋ฒจ์—์„œ๋„ ์ง€๋‚œ๋ฐค์— ์•ผ์‹์œผ๋กœ ๋จน์€ ๋ผ๋ฉด ๋ฉด๋ฐœ์ฒ˜๋Ÿผ ๊ผฌ์—ฌ์žˆ๋Š” ๋ถ€๋ถ„๋“ค์„ ๋ณด๋‹ค ๊ฐœ๋ฐœํ•˜๊ธฐ ํŽธํ•˜๊ณ  ์œ ์ง€ ๋ณด์ˆ˜๊ฐ€ ์šฉ์ดํ•˜๊ฒŒ ๊ตฌ์กฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ‘์ •๋ฆฌ’์˜ ์Šต๊ด€ ๋˜ํ•œ ๊ธ€์“ฐ๊ธฐ๋ฅผ ํ†ตํ•ด์„œ ์ˆ˜๋ จ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ‘๊ผผ๊ผผํ•จ’์„ ๊ธฐ๋ฅด๋Š” ๋ฐ์—๋Š” ๊ธ€์“ฐ๊ธฐ๋งŒ ํ•œ ๊ฒŒ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

ใ€€์šฐ๋ฆฌ๋Š” ๋‹ค์–‘ํ•œ ๊ฐœ๋ฐœ ์–ธ์–ด๋กœ ์ฝ”๋”ฉ์„ ํ•˜๊ณค ํ•œ๋‹ค. ์™œ ์ฝ๊ธฐ์ข‹์€ ์ฝ”๋“œ๊ฐ€ ์ข‹์€ ์ฝ”๋“œ๋ผ๋Š” ์ฑ…์ด ์žˆ๋“ฏ์ด ๊ฒฐ๊ตญ ์ฝ”๋”ฉ ๋˜ํ•œ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์ด ์ผ์ข…์ด๋ผ ์ƒ๊ฐํ•œ๋‹ค. ๋‚ด๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ๋กœ์ง์„ ๊ฐœ๋ฐœ ์–ธ์–ด๋กœ ์ฝ”๋”ฉ์„ ํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด๋ฉด, ๊ฒฐ๊ตญ ๋‚ด๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ๋กœ์ง์ด ๋ช…๋ฃŒํ•˜๊ณ  ์ •๋ฆฌ๊ฐ€ ์ž˜ ๋œ ์ƒํƒœ์—์„œ์•ผ ์ฝ”๋“œ ๋˜ํ•œ ์†Œ์œ„ ‘์ฝ๊ธฐ ์ข‹์€ ์ฝ”๋“œ’๊ฐ€ ๋˜์ง€ ์•Š์„๊นŒ ์‹ถ๋‹ค.

ใ€€๋ธ”๋กœ๊ทธ๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ ์–ด๋””์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์•ผ ํ•˜๋‚˜ ๋ง‰๋ง‰ํ•˜๋‹ค๋ฉด, ์˜ค๋Š˜์˜ ๋ฐฐ์šด ๋‚ด์šฉ (๊ฐœ๋ฐœ์ž๋“ค ์‚ฌ์ด์—์„œ ์œ ํ–‰์ฒ˜๋Ÿผ ๋ฒˆ์ง€๊ณ  ์žˆ๋Š” TIL์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•ด ๋ณด๋Š” ๊ฒƒ๋ถ€ํ„ฐ ์ถ”์ฒœํ•œ๋‹ค. ๊ฒฝ๋ ฅ์ด 1๋…„ ์ฐจ์—ฌ๋„ 10๋…„ ์ฐจ์—ฌ๋„ ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค ๋ณด๋ฉด ์ƒˆ๋กœ์šด ๊ฒƒ์„ ๋ฐœ๊ฒฌํ•˜๊ธฐ ๋งˆ๋ จ์ด๋‹ค. ๊ทธ๋ ‡๊ฒŒ ์กฐ๊ธˆ์”ฉ ์ ์ ˆํ•œ ๋ธ”๋กœ๊ทธ ํ”Œ๋žซํผ์— ์ •๋ฆฌ๋ฅผ ํ•ด ๋‚˜๊ฐ€๋‹ค ๋ณด๋ฉด ์–ด๋А์ƒˆ ์ž์‹ ๋งŒ์˜ ๊ฐœ๋ฐœ ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ ๋งŒ๋“ค์–ด์ง€๊ณ , ๋‚˜์•„๊ฐ€ ๊ธ€์“ฐ๊ธฐ๊ฐ€ ์ „ํ•ด์ฃผ๋Š” ๊ธ์ •์ ์ธ ํšจ๊ณผ๋ฅผ ๋งŒ๋ฝํ•˜๋ฆฌ๋ผ ์ž๋ถ€ํ•œ๋‹ค.

๊ทธ๋Ÿฐ ๊ฐœ๋ฐœ์ž๋กœ ๊ดœ์ฐฎ์€๊ฐ€ - '๋ฌธํ™”' ํŽธ

ใ€€ํ•œ๋™์•ˆ ๊ธ€์„ ์“ฐ์ง€ ์•Š์•˜๋‹ค. ๊ธ€์„ ์“ฐ์ง€ ์•Š์€ ๊ฒƒ์ผ๊นŒ ์“ฐ์ง€ ๋ชปํ•œ ๊ฒƒ์ผ๊นŒ. ์ด๋Ÿฐ์ €๋Ÿฐ ์ด์œ ๋กœ ๋ฒˆ์•„์›ƒ ๋Šช์— ๋น ์ ธ๋ฒ„๋ ค ์•„๋ฌด๊ฒƒ๋„ ํ•˜๊ธฐ ์‹ซ์–ด์„œ๋ผ๋Š” ํ•‘๊ณ„๊ฐ€ ์–ด์šธ๋ฆด ์ˆ˜๋„ ์žˆ๊ฒ ๋‹ค๋งŒ. ์š”์ฆ˜ ๋“ค์–ด ๋”์šฑ๋” ๋ฌด๊ธฐ๋ ฅํ•จ์ด ๊ทน๋„๋กœ ๋ฟœ๋ฟœ๋Œ€๋Š” ๊ฐ€์šด๋ฐ ๋ฌธ๋“, ๊ฐœ๋ฐœ์ž๋กœ์จ ์–ผ๋งˆ๋‚˜ ์ž˜ ์ง€๋‚ด์™”๋Š”๊ฐ€ ๋’ค๋ฅผ ๋Œ์•„๋ณด๊ณ  ์‹ถ์—ˆ๋‹ค. ์•ž๋งŒ ๋ณด๊ณ  ๋‹ฌ๋ฆฌ๋Š” ๊ฒƒ๋ณด๋‹ค ๋‚ด ์ƒ๊ฐ๊ณผ ๋‚ด ํ˜ธํก์„ ์ ๊ฒ€ํ•˜๋Š” ๊ฒƒ ๋˜ํ•œ ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๊ธฐ์— ๋‹น๋ถ„๊ฐ„์€ ๋” ๋‚˜์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๊ธฐ ์œ„ํ•œ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ฃผ์ œ๋กœ ๊ธ€์„ ์จ๋ณด๋ ค ํ•œ๋‹ค. ์ด๋ฆ„ํ•˜์—ฌ ๊ทธ๋Ÿฐ ๊ฐœ๋ฐœ์ž๋กœ ๊ดœ์ฐฎ์€๊ฐ€ XX ํŽธ

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

ใ€€๊ฐœ๋ฐœ์ž๋กœ ์‚ด์•„๊ฐ€๋Š” ๋ฐ ์žˆ์–ด ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒŒ ๋ฌด์—‡์ผ๊นŒ? ๋ฌผ๋ก  ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ์ˆ ์ด ๊ฐ€์žฅ ์ค‘์š”ํ•˜๊ฒ ์ง€๋งŒ ๋ช‡ ๋…„ ์ „๋ถ€ํ„ฐ ๊ธฐ์ˆ ์˜ ๋ฐœ์ „์ด ๊ธ‰๋ณ€ํ•˜๋Š” ์„ธ์ƒ ์†์—์„œ ๊ณผ์—ฐ ๊ธฐ์ˆ ๋งŒ์ด ์ค‘์š”ํ• ๊นŒ? ๊ธฐ์ˆ ๋งŒ ์ž˜ ์•Œ๊ณ  ์žˆ์œผ๋ฉด ๋ณต์žกํ•˜๊ฒŒ ๊ผฌ์ธ ์ŠคํŒŒ๊ฒŒํ‹ฐ ๋ฉด ๊ฐ™์€ ๋ฌธ์ œ ๋งŽ์€ ์ฝ”๋“œ๋ฅผ ์ˆ ์ˆ  ํ’€์–ดํ—ค์น˜๊ณ , ์–ธ์ œ ์–ด๋””์„œ๋“  ๊ฐœ๋ฐœ์ž๋กœ์จ ํ–‰๋ณตํ•œ ์‚ถ์„ ์˜์œ ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

ใ€€์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ์š”์†Œ๋“ค ์ค‘ ๊ฐ€์žฅ ์ฒซ ๋ฒˆ์งธ๋กœ ๋– ์˜ค๋ฅด๋Š” ํ‚ค์›Œ๋“œ๋Š” ๋ฐ”๋กœ ๋ฌธํ™”(Culture)๊ฐ€ ์•„๋‹๊นŒ ์‹ถ๋‹ค. ๊ทธ๋Ÿผ ์™œ ๋ฌธํ™”๊ฐ€ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ค‘์š”ํ•˜๊ณ  ์–ด๋–ค ์‹์œผ๋กœ ๋ฌธํ™”๋ฅผ ๋งŒ๋“ค์–ด ๊ฐ€๋Š” ๊ฒŒ ์ข‹์„์ง€์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

/images/a-good-developer-in-terms-of-culture/dailymetting.jpg
๊ฐ ํŒ€์— ๋งž๋Š” ๋ฌธํ™”๋Š” ๋ชจ๋‘๋ฅผ ์„ฑ์žฅ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
์ถœ์ฒ˜ : https://steemkr.com/kr-dev/@dreamisnowhere/5squ7b

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

์ฝ”๋“œ๋ฆฌ๋ทฐ

ใ€€ํŒ€์— ์†ํ•ด์„œ ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค ๋ณด๋ฉด ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ๋™์‹œ์— ์ž‘์—…ํ•˜๊ณค ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ํ˜•์ƒ๊ด€๋ฆฌ ๋„๊ตฌ (์š”์ฆ˜ git ์„ ์•ˆ ์“ฐ๋Š” ๊ณณ์ด ์—†์„ ์ •๋„…)๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋™์‹œ์— ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•ด๋„ ์ „ํ˜€ ๋ฌด๋ฆฌ๊ฐ€ ์—†์„ ์ •๋„์ธ๋ฐ ๊ฒฐ๊ตญ ์ž‘์—…ํ•œ ๊ฒฐ๊ณผ๋ฌผ์„ ํ•œ ๊ณณ์œผ๋กœ ๋ณ‘ํ•ฉ (merge) ํ•ด์•ผ ํ•˜๋Š” ์‹œ์ ์ด ์˜ค๊ธฐ ๋งˆ๋ จ์ด๊ณ  ๊ทธ๋•Œ์—” (์˜จ๋ผ์ธ/์˜คํ”„๋ผ์ธ) ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ํ•˜๊ฒŒ ๋œ๋‹ค. ์–ด๋– ํ•œ ์‚ฌ์—ฐ์œผ๋กœ ์ฝ”๋“œ ๋ฆฌ๋ทฐ ์—†์ด ๋นจ๋ฆฌ merge ํ•ด์•ผ ํ•˜๋Š” ๊ฑด ์ดํ•ด๋˜์ง€๋งŒ ๊ฐ€๊ธ‰์  ํ•œ ๋ช… ์ด์ƒ์˜ ๋ฆฌ๋ทฐ์–ด๊ฐ€ ์Šน์ธ์„ ํ•œ ๋’ค์— merge ๊ฐ€ ๋ผ์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค. (pullRequest๋ฅผ ๋‹จ์ˆœ merge ์šฉ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฑด ์ •๋ง ์ž˜๋ชป๋œ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜) ์ค‘๋ณต๋œ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์—ˆ๊ฑฐ๋‚˜ ์ž‘์—…์ž๊ฐ€ ์˜ˆ์ƒํ•˜์ง€ ๋ชปํ•œ ๋ถ€๋ถ„๋“ค์„ ๋ฆด๋ฆฌ์Šค ์ „์— ์„œ๋กœ ์ด์•ผ๊ธฐํ•ด๋ณด๋ฉด์„œ ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ํŒ€ ์ปจ๋ฒค์…˜, ์„ค๊ณ„/๊ตฌ์กฐ๋ฅผ ๋” ํšจ์œจ์ ์œผ๋กœ ๊ฐ€์ ธ๊ฐˆ ์ˆ˜ ์žˆ๋Š” ์ ˆํ˜ธ์˜ ์ฐฌ์Šค.

ใ€€์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ํฌ์ธํŠธ๋Š” ๋ฆฌ๋ทฐ๋ฅผ ๋ฐ›๋Š” ‘๋ฆฌ๋ทฐ์ด’ ์™€ ๋ฆฌ๋ทฐ๋ฅผ ํ•ด์ฃผ๋Š” ‘๋ฆฌ๋ทฐ์–ด’๋“ค์˜ ๋ฌธํ™”์ ์ธ ์ธก๋ฉด์—์„œ ์ƒ๊ฐ์„ ํ•ด๋ณผ ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

  • ๋ฆฌ๋ทฐ์ด(Reviewee)
    • ๋ฆฌ๋ทฐ์–ด์˜ ์†Œ์ค‘ํ•œ ์‹œ๊ฐ„์„ ํ• ์• ํ•ด์„œ ์ž์‹ ์˜ ์ฝ”๋“œ๊ฐ€ ์ด์ƒ์ด ์—†๋Š”์ง€์— ๋Œ€ํ•œ ‘๋„์›€’์„ ์š”์ฒญํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ตœ๋Œ€ํ•œ ์„ค๋ช…์„ ์ž˜ ์ ์–ด์„œ ๋ฆฌ๋ทฐํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ค„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
    • ์ž‘์—…์„ ํ•˜๋‹ค ๋ณด๋ฉด ํ•œ ๋ฒˆ์— ๋ชฐ์•„์„œ ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ๋ฐ›๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋Œ€๋ถ€๋ถ„์ด์ง€๋งŒ ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ ์ธก๋ฉด๊ณผ ์ฝ”๋“œ ๋ฆฌ๋ทฐ ์‹œ๊ฐ„์„ ์ค„์ด๋Š” ์ธก๋ฉด์—์„œ๋Š” ์ตœ๋Œ€ํ•œ ์ž‘์€ ๋‹จ์œ„๋กœ ๋ฆฌ๋ทฐ๋ฅผ ์š”์ฒญํ•ด์•ผ ํ•œ๋‹ค.
    • ๋ฆฌ๋ทฐ๊ฐ€ ์ง„ํ–‰์ด ๋˜์ง€ ๋ชปํ•˜์—ฌ ๋‹ค์Œ ์ž‘์—… ๋˜ํ•œ ์ง„ํ–‰์„ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธฐ๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์ตœ๋Œ€ํ•œ ์ฝ”๋“œ ๋ฆฌ๋ทฐ ๋ฐ›๋Š” ๋ถ€๋ถ„๊ณผ ์˜์กด์„ฑ์ด ์—†๋„๋ก ์ž‘์—…์ด ๋ผ์•ผ ํ•˜๋ฉฐ ๊ทธ๋„ ์•„๋‹ˆ๋ผ๋ฉด ์ •์ค‘ํ•˜๊ฒŒ ๋ฆฌ๋ทฐ์–ด์—๊ฒŒ ‘๋ถ€ํƒ’์„ ํ•ด์•ผ ํ•œ๋‹ค. (์š”์ฒญ ์ด ์•„๋‹ˆ๋ผ๋Š” ์ !)
    • ๋ฆฌ๋ทฐ์–ด์˜ ๋ฆฌ๋ทฐ๋Š” “์ง€์ ” ์ด ์•„๋‹ˆ๋ผ “ํ•จ๊ป˜ ์ž‘์—…ํ•˜๋Š” ์ฝ”๋“œ์— ๋Œ€ํ•œ ์กฐ์–ธ"์œผ๋กœ ๋ฐ›์•„๋“ค์—ฌ์•ผ ํ•œ๋‹ค. ํ˜น ๋ฆฌ๋ทฐ ๋‚ด์šฉ์ด ์ž์‹ ์˜ ์ƒ๊ฐ๊ณผ ๋‹ค๋ฅด๋‹ค๋ฉด ํ† ๋ก ์„ ํ†ตํ•ด ํ•ฉ์˜์ ์„ ์ฐพ๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค. (๋ฌด์กฐ๊ฑด ๋ฆฌ๋ทฐ์–ด๊ฐ€ ๋ฆฌ๋ทฐํ–ˆ๋‹ค๊ณ  ๊ธฐ๊ณ„์ ์œผ๋กœ ๊ณ ์น˜๋Š” ๊ฒƒ ๋˜ํ•œ ์ž˜๋ชป๋œ ๋ถ€๋ถ„)
  • ๋ฆฌ๋ทฐ์–ด(Reviewer)
    • ๋ฆฌ๋ทฐ์ด๋Š” ๋‹น์‹ ์˜ ํ•œ๋งˆ๋””๋ฅผ ๊ฐ„์ ˆํ•˜๊ฒŒ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์„ ์ˆ˜๋„ ์žˆ์œผ๋‹ˆ ์ตœ๋Œ€ํ•œ ์ •์„ฑ๊ป ๋ฆฌ๋ทฐ๋ฅผ ํ•ด์ฃผ์ž.
    • ์˜จ๋ผ์ธ ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด “ํ…์ŠคํŠธ"๋ผ๋Š” ์ œํ•œ์ ์ธ ์ƒํ™ฉ์—์„œ ์ตœ๋Œ€ํ•œ ์œ ์—ฐํ•œ ๋ฉ˜ํŠธ๋กœ ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค. (์ž์นซ ์ž˜๋ชปํ•˜๋‹ค๊ฐ„ ์„œ๋กœ ์˜คํ•ด๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ…)

์ฝ”๋“œ ๋ฆฌ๋ทฐ ๊ด€๋ จ๋œ ๋ฌธํ™”์— ๋Œ€ํ•œ ๋‚ด์šฉ๋“ค์€ ์ž ๊น๋งŒ ๊ฒ€์ƒ‰ํ•ด๋ด๋„ ํ›Œ๋ฅญํ•œ ํฌ์ŠคํŒ…๋“ค์ด ๋‚˜์˜ค๋‹ˆ ์ฐธ๊ณ ํ•ด๋ด๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค. Line | ํšจ๊ณผ์ ์ธ ์ฝ”๋“œ๋ฆฌ๋ทฐ๋ฅผ ์œ„ํ•ด์„œ Kakao | ์ฝ”๋“œ ๋ฆฌ๋ทฐ, ์–ด๋””๊นŒ์ง€ ํ•ด๋ดค๋‹ˆ? Jandi | ์ฝ”๋“œ๋ฆฌ๋ทฐ, ์ด๋ ‡๊ฒŒ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์Šคํ”„๋ง ๋ถ€ํŠธ์— ํ•„ํ„ฐ๋ฅผ '์กฐ์‹ฌํ•ด์„œ' ์‚ฌ์šฉํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•

์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ค‘๋ณต์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ๋‚ด์šฉ์„ ํ•œ๊ณณ์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๊ฑฐ๋‚˜ ์„œ๋น„์Šค์˜ ๋‹ค์–‘ํ•œ ๋‹ˆ์ฆˆ๋ฅผ ์ถฉ์กฑ์‹œํ‚ค๊ธฐ์— ์•ˆ์„ฑ๋งž์ถค์ธ ์žฅ์น˜์ธ๊ฒƒ ๊ฐ™๋‹ค. ํ•„ํ„ฐ๋ž€ ๋ฌด์—‡์ธ๊ฐ€ ์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ ์›Œ๋‚™์— ๋‹ค๋ฅธ ๋ธ”๋กœ๊ทธ๋‚˜ ๊ณต์‹ ๋„ํ๋จผํŠธ์—์„œ ์ž์„ธํ•˜๊ฒŒ ๊ทธ๋ฆฌ๊ณ  ๋‹ค์–‘ํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๊ณ  ์žˆ๊ธฐ์— ๊ธฐ๋ณธ ๊ฐœ๋…์— ๋Œ€ํ•ด์„œ๋Š” ์„ค๋ช…ํ•˜์ง€ ์•Š๋„๋ก ํ•˜๋ ค ํ•œ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์–ด๋…ธํ…Œ์ด์…˜์ด๋ผ๋Š” ๊ฐ„ํŽธํ•จ์— ์ทจํ•ด(?) “๋Œ๊ฒฉ ์•ž์œผ๋กœ, ๋‹ฅ๊ณต” ์˜ ์ž์„ธ๋กœ ๊ฐœ๋ฐœ์„ ํ•˜๋ คํ–ˆ๋˜ ํ•„์ž๋ฅผ ๋ณด๊ณ  “๋ฐ˜์„ฑ"์˜ ์ž์„ธ๋กœ ํ•„ํ„ฐ๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋ช…ํ™•ํ•˜๊ฒŒ ์ •๋ฆฌ๋ฅผ ํ•˜๊ณ ์ž ํ•œ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ๋Š” ์•„์ฃผ ๊ฐ„๋‹จํ•˜๋ฉด์„œ๋„ ์—„์ฒญ๋‚˜๊ฒŒ ์œ„ํ—˜ํ•œ ํ•„ํ„ฐ ์„ค์ • ์‚ฌ๋ก€์— ๋Œ€ํ•ด์„œ๋„ ์งš๊ณ  ๋„˜์–ด๊ฐ€๋ณด์ž. ๊ทธ๋ƒฅ ๋„˜์–ด๊ฐ€๋ฉด ์•„์‰ฌ์šฐ๋‹ˆ, ํ•œ๋ฒˆ์ด๋ผ๋„ ‘spring’ ์ด๋ผ๋Š” framework ๋ฅผ ์ ‘ํ•ด๋ณธ ์‚ฌ๋žŒ์ด๋ผ๋ฉด ๋ดค์„๋ฒ•ํ•œ ๊ทธ๋ฆผ์„ ์ฒจ๋ถ€ํ•˜๋Š”๊ฒƒ์œผ๋กœ ํ•„ํ„ฐ๋ž€ ๋ฌด์—‡์ธ๊ฐ€ ์— ๋Œ€ํ•œ ์„ค๋ช…์„ ๋Œ€์‹ ํ•˜๋Š”๊ฒŒ ์ข‹๊ฒ ๋‹ค.

/images/spring-boot-filter/spring-request-lifecycle.jpg
์ถœ์ฒ˜ : https://justforchangesake.wordpress.com/2014/05/07/spring-mvc-request-life-cycle/

๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•˜๊ธฐ ์ „์— ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉ๋  ํ•„ํ„ฐ์™€ ์ปจํŠธ๋กค๋Ÿฌ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ํ•„ํ„ฐ
@Slf4j
public class MyFilter implements Filter {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		log.info("init MyFilter");
	}

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
		throws IOException, ServletException {
		log.info("doFilter MyFilter, uri : {}", ((HttpServletRequest)servletRequest).getRequestURI());
		filterChain.doFilter(servletRequest, servletResponse);
	}

	@Override
	public void destroy() {
		log.info("destroy MyFilter");
	}
}
  • ํ…Œ์ŠคํŠธ ํ•  ์ปจํŠธ๋กค๋Ÿฌ
@Slf4j
@RestController
public class SampleController {

	@GetMapping("/test")
	public String test() {
		return "test";
	}

	@GetMapping("/filtered/test")
	public String filteredTest() {
		return "filtered";
	}
}

๋ฐฉ๋ฒ• 1 : FilterRegistrationBean

์•„์ฃผ ๊ฐ„๋‹จํ•˜๊ฒŒ, ์ผ๋ฐ˜ url ํ•˜๋‚˜์™€ ํ•„ํ„ฐ์— ์ ์šฉํ•  url ๋‘๊ฐœ๋ฅผ ๋งŒ๋“ค๊ณ  ์„ค์ •ํ•˜๋ ค ํ•œ๋‹ค. FilterRegistrationBean ์„ ์ด์šฉํ•ด์„œ ์œ„์—์„œ ๋งŒ๋“ค์—ˆ๋˜ ํ•„ํ„ฐ๋ฅผ ์•„๋ž˜์ฒ˜๋Ÿผ ๋“ฑ๋กํ•ด๋ณด์ž.

@SpringBootApplication
public class Method1Application {

	public static void main(String[] args) {
		SpringApplication.run(Method1Application.class, args);
	}

	@Bean
	public FilterRegistrationBean setFilterRegistration() {
		FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
		// filterRegistrationBean.setUrlPatterns(Collections.singletonList("/filtered/*")); // list ๋ฅผ ๋ฐ›๋Š” ๋ฉ”์†Œ๋“œ
		filterRegistrationBean.addUrlPatterns("/filtered/*"); // string ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ ๊ฐ€๋ณ€์ธ์ž๋กœ ๋ฐ›๋Š” ๋ฉ”์†Œ๋“œ
		return filterRegistrationBean;
	}
}

์œ„ ์ฃผ์„์—๋„ ์ ์—ˆ์ง€๋งŒ filterRegistrationBean ์˜ “setUrlPatterns” ์™€ “addUrlPatterns” ์˜ ์ฐจ์ด๋Š” ๋ณ„๊ฑฐ ์—†๋‹ค. list ์ž์ฒด๋ฅผ ๋ฐ›์„๊ฑด์ง€ ์•„๋‹ˆ๋ฉด ๊ฐ€๋ณ€์ธ์ž๋กœ ๊ณ„์† ์ถ”๊ฐ€ ํ• ๊ฒƒ์ธ์ง€. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด “/filtered/“์œผ๋กœ “์‹œ์ž‘"ํ•˜๋Š” ํŒจํ„ด์˜ url์˜ ์š”์ฒญ์ด ์˜ค๊ฒŒ ๋˜๋ฉด ๋“ฑ๋กํ•œ ํ•„ํ„ฐ๋ฅผ ํ†ต๊ณผํ•˜๊ฒŒ ๋œ๋‹ค.

  • ์‹คํ–‰ : ํ•„ํ„ฐ ์ƒ์„ฑ
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.6.RELEASE)

2020-04-06 23:45:01.225  INFO 14672 --- [           main] c.t.s.method1.Method1Application         : No active profile set, falling back to default profiles: default
2020-04-06 23:45:02.153  INFO 14672 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-04-06 23:45:02.168  INFO 14672 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-04-06 23:45:02.168  INFO 14672 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.33]
2020-04-06 23:45:02.361  INFO 14672 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-04-06 23:45:02.362 DEBUG 14672 --- [           main] o.s.web.context.ContextLoader            : Published root WebApplicationContext as ServletContext attribute with name [org.springframework.web.context.WebApplicationContext.ROOT]
2020-04-06 23:45:02.362  INFO 14672 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1082 ms
2020-04-06 23:45:02.391 DEBUG 14672 --- [           main] o.s.b.w.s.ServletContextInitializerBeans : Mapping filters: filterRegistrationBean urls=[/filtered/*] order=2147483647, characterEncodingFilter urls=[/*] order=-2147483648, formContentFilter urls=[/*] order=-9900, requestContextFilter urls=[/*] order=-105
2020-04-06 23:45:02.391 DEBUG 14672 --- [           main] o.s.b.w.s.ServletContextInitializerBeans : Mapping servlets: dispatcherServlet urls=[/]
2020-04-06 23:45:02.409 DEBUG 14672 --- [           main] o.s.b.w.s.f.OrderedRequestContextFilter  : Filter 'requestContextFilter' configured for use
2020-04-06 23:45:02.409 DEBUG 14672 --- [           main] s.b.w.s.f.OrderedCharacterEncodingFilter : Filter 'characterEncodingFilter' configured for use

// ํ•„ํ„ฐ๊ฐ€ ์ƒ์„ฑ ๋˜์—ˆ๋‹ค!
2020-04-06 23:45:02.410  INFO 14672 --- [           main] c.t.springbootfilter.method1.MyFilter    : init MyFilter

2020-04-06 23:45:02.410 DEBUG 14672 --- [           main] o.s.b.w.s.f.OrderedFormContentFilter     : Filter 'formContentFilter' configured for use
2020-04-06 23:45:02.544  INFO 14672 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
  • ์ผ๋ฐ˜ url
2020-04-06 23:45:27.526 DEBUG 14672 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : GET "/test", parameters={}
2020-04-06 23:45:27.528 DEBUG 14672 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.taetaetae.springbootfilter.method1.SampleController#test()
2020-04-06 23:45:27.548 DEBUG 14672 --- [nio-8080-exec-1] m.m.a.RequestResponseBodyMethodProcessor : Using 'text/html', given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
2020-04-06 23:45:27.548 DEBUG 14672 --- [nio-8080-exec-1] m.m.a.RequestResponseBodyMethodProcessor : Writing ["test"]
2020-04-06 23:45:27.555 DEBUG 14672 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
  • ํ•„ํ„ฐ๋ง url
// ํ•„ํ„ฐ์— ๋“ค์–ด์˜จ๊ฒƒ ํ™•์ธ!
2020-04-06 23:45:37.455  INFO 14672 --- [nio-8080-exec-2] c.t.springbootfilter.method1.MyFilter    : doFilter MyFilter, uri : /filtered/test

2020-04-06 23:45:37.456 DEBUG 14672 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : GET "/filtered/test", parameters={}
2020-04-06 23:45:37.456 DEBUG 14672 --- [nio-8080-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.taetaetae.springbootfilter.method1.SampleController#filteredTest()
2020-04-06 23:45:37.457 DEBUG 14672 --- [nio-8080-exec-2] m.m.a.RequestResponseBodyMethodProcessor : Using 'text/html', given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
2020-04-06 23:45:37.457 DEBUG 14672 --- [nio-8080-exec-2] m.m.a.RequestResponseBodyMethodProcessor : Writing ["filtered"]
2020-04-06 23:45:37.459 DEBUG 14672 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Completed 200 OK

๋ฐฉ๋ฒ• 2 : @WebFilter + @ServletComponentScan

@ServletComponentScan ์–ด๋…ธํ…Œ์ด์…˜์„ @Configuration ์–ด๋…ธํ…Œ์ด์…˜์ด ์„ค์ •๋˜์–ด ์žˆ๋Š”๊ณณ์— ๊ฑธ์–ด์ค€ ๋‹ค์Œ ์œ„์—์„œ ์„ค์ •ํ•œ ํ•„ํ„ฐ์— @WebFilter ์–ด๋…ธํ…Œ์ด์…˜์„ ์„ค์ •ํ•ด์ฃผ๋ฉด ์•„์ฃผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋์ด ๋‚œ๋‹ค.

์กฐ๊ธˆ ๋” ๊ดœ์ฐฎ์€ Rest Template 2๋ถ€ - Circuit-breaker

์ง€๋‚œ ํฌ์ŠคํŒ…์—์„œ๋Š” Retryable ๋ฅผ ํ™œ์šฉํ•ด์„œ ๊ฐ„ํ—์ ์ธ ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๋ฅผ “์žฌ์‹œ๋„"๋ฅผ ํ•จ์œผ๋กœ์จ ์•„์ฃผ ๊ฐ„๋‹จํ•˜๋ฉด์„œ๋„ ๊ฐ•๋ ฅํ•˜๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜๋‹ค. ์‹ค์ œ๋กœ ํ•„์ž๊ฐ€ ์šด์˜ํ•˜๋Š” ์„œ๋น„์Šค ์—์„œ๋„ Retryable ๋ฅผ ์ด์šฉํ•˜๊ธฐ ์ „๊ณผ ํ›„๋ฅผ ๋น„๊ตํ•ด๋ณด๋ฉด ๊ฐ„ํ—์ ์ธ ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜์˜ ๋นˆ๋„์ˆ˜๊ฐ€ ํ™•์‹คํžˆ ์ค„์–ด๋“ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

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

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

๊ธฐ์กด ํ•œ๋ฉ์–ด๋ฆฌ๋กœ ๊ด€๋ฆฌ๋˜๋˜ Monolithic Architecture ์—์„œ๋Š” ์ž์ฒด์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ์—๋Ÿฌ ์ปจํŠธ๋กค ๋˜ํ•œ ์ž์ฒด์ ์œผ๋กœ ๊ด€๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ชจ๋“ˆ์ด ๋ชจ๋“ˆ์„ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋Š” Microservice Architecture ๋กœ ๋ฐ”๋€Œ๋‹ค๋ณด๋‹ˆ ์ด๋Ÿฐ “์—ฐ์‡„ ์žฅ์• (?)” ๊ฐ™์€ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ํ˜ธ์ถœ์„ ๋ฐ›๋Š” ์„œ๋ฒ„์˜ ์ƒํƒœ๊ฐ€ ์ด์ƒํ•˜๋ฉด (์—๋Ÿฌ์‘๋‹ต์ด ์ง€์ •ํ•œ ์ž„๊ณ„์น˜๋ฅผ ๋ฒ—์–ด๋‚˜๋Š” ์ˆ˜์ค€์œผ๋กœ ๋งž์ถฐ์„œ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด) ์ ์ ˆํ•˜๊ฒŒ ํ˜ธ์ถœ์„ ํ•˜์ง€ ์•Š๊ณ  (2์ฐจ ์žฅ์• ๋ฅผ ๋‚ด์ง€ ์•Š๋„๋ก ํ˜ธ์ถœ ์ž์ฒด๋ฅผ ํ•˜์ง€ ์•Š๊ณ ) ์–ด๋А์ •๋„ ๊ธฐ๋‹ค๋ฆฌ๋‹ค ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ๋Š” ์—๋Ÿฌ์‘๋‹ต์ด ์•„๋‹Œ ๋ฏธ๋ฆฌ ์ •ํ•ด๋‘” ์‘๋‹ต์„ ๋‚ด๋ ค์ฃผ๊ณ , ์—๋Ÿฌ๊ฐ€ ๋ณต๊ตฌ๋˜๋ฉด ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๋„๋ก ํ•˜๋Š” “๋ฌด์–ธ๊ฐ€” ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์„๊นŒ?

/images/better-rest-template-2-netflix-hystrix/domino.gif
์—ฐ์‡„ ์žฅ์• . ์ œ๋ฐœ ๋ฉˆ์ถฐ…
์ถœ์ฒ˜ : http://dpg.danawa.com/mobile/community/view?boardSeq=175&listSeq=4066389

์ง€๋‚œ ํฌ์ŠคํŒ…์— ์ด์–ด ์ด๋ฒˆ ํฌ์ŠคํŒ… ์—์„œ๋Š” ๊ทธ “๋ฌด์–ธ๊ฐ€”. ์ฆ‰, Circuit-breaker ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ณ  ์ง์ ‘ ๊ตฌํ˜„ ๋ฐ ํ…Œ์ŠคํŠธ ํ•˜๋ฉด์„œ ๋Œ์•„๊ฐ€๋Š” ์›๋ฆฌ์— ๋Œ€ํ•ด ์ดํ•ด ํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค. ๋ง‰์ƒ ๊ฐœ๋…์€ ๋จธ๋ฆฟ์†์— ์žˆ์ง€๋งŒ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด์ง€ ์•Š์œผ๋ฉด ๋‚ด๊ฒƒ์ด ์•„๋‹ˆ๊ธฐ์—, ์ง์ ‘ ๊ตฌํ˜„ํ•˜๊ณ  ์„ค์ •๊ฐ’๋“ค์„ ๋ฐ”๊ฟ”๊ฐ€๋ฉด์„œ ์–ธ์  ๊ฐ€ ํ•„์š”ํ•œ ์ˆœ๊ฐ„์— ๊บผ๋‚ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋‚˜๋งŒ์˜ “๋ฌด๊ธฐ” ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ณ ์ž ํ•œ๋‹ค.

Circuit breaker ?

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

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

์—ฌ๊ธฐ์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ฌธ์žฅ์€ “ํ”ผํ•ด๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด ์ž๋™์œผ๋กœ ํšŒ๋กœ๋ฅผ ์ •์ง€์‹œํ‚ค๋Š””, “์–ด๋А์ •๋„ ์‹œ๊ฐ„์ด ์ง€๋‚œ๋’ค ์›๋ž˜์˜ ๊ธฐ๋Šฅ์ด ๋™์ž‘ํ•˜๋„๋ก ๋ณต๊ท€๋œ๋‹ค” ์ด ๋ถ€๋ถ„์ด ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒƒ ๊ฐ™๋‹ค. ์‹œ์Šคํ…œ ๊ตฌ์„ฑ์ด ์ ์  Microservice Architecture ๋กœ ๋ฐ”๋€Œ์–ด ๊ฐ€๋Š” ์‹œ์ ์—์„œ ์ด๋Ÿฌํ•œ “์„œํ‚ท๋ธŒ๋ ˆ์ด์ปค"๋Š” ์ž๋™์œผ๋กœ ๋ชจ๋“ˆ๊ฐ„์˜ ํ˜ธ์ถœ ์—๋Ÿฌ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ์œ„์—์„œ ๋งํ•œ “์—ฐ์‡„ ์žฅ์• "๋ฅผ ์‚ฌ์ „์— ๋ง‰์„ ์ˆ˜ ์žˆ๋Š” ์•„์ฃผ ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ์ด๋ผ ์ƒ๊ฐ๋œ๋‹ค.

“circuit breaker spring” ์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๋กœ ๊ฒ€์ƒ‰ํ•ด๋ณด๋ฉด ์ด๋Ÿฌํ•œ ๊ณ ๋ฏผ์„ ์ด๋ฏธ Netflix ๋ผ๋Š” ํšŒ์‚ฌ์—์„œ Hystrix ๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๊ฐœ๋ฐœ์ด ๋œ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ์ด core ๋ชจ๋“ˆ์„ Spring ์—์„œ ํ•œ๋ฒˆ ๋” ๊ฐ์‹ธ์„œ Spring Boot ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹๊ฒŒ spring-cloud-starter-netflix-hystrix ๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๋งŒ๋“ค์–ด ๋‘” ๊ฒƒ์ด ์žˆ๋Š”๋ฐ ์ด๊ฒƒ์„ ํ™œ์šฉํ•ด ๋ณด๊ธฐ๋กœ ํ•˜์ž.

๊ตฌํ˜„

๋Š˜ ๊ทธ๋žฌ๋“ฏ์ด SpringBoot ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ํ…Œ์ŠคํŠธํ•  Controller ๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ์ž. ์›๋ž˜๋Œ€๋กœ๋ผ๋ฉด ํ˜ธ์ถœ์„ ํ•˜๋Š” ๋ชจ๋“ˆ๊ณผ ํ˜ธ์ถœ์„ ๋ฐ›๋Š” ๋ชจ๋“ˆ, 2๊ฐœ์˜ ๋ชจ๋“ˆ์„ ๋งŒ๋“ค์–ด์„œ ํ…Œ์ŠคํŠธ ํ•ด์•ผ ํ•˜์ง€๋งŒ ํŽธ์˜๋ฅผ ์œ„ํ•ด ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ์—์„œ ๋‘๊ฐœ์˜ Controller ์„ ๋งŒ๋“ค๊ณ  ํ…Œ์ŠคํŠธ ํ•ด๋ณด๋Š” ๊ฒƒ์œผ๋กœ ํ•˜์ž.

@RestController
public class MainController {

	private final MainService mainService;

	@GetMapping("index")
	public String index(String key){
		return mainService.getResult(key);
	}

	public MainController(MainService mainService) {
		this.mainService = mainService;
	}
}

@Slf4j
@Service
public class MainService {

	private RestTemplate restTemplate;

	public String getResult(String key) {
		return restTemplate.getForObject("http://localhost:8080/target?key=" + key, String.class);
	}

	public MainService(RestTemplate restTemplate) {
		this.restTemplate = restTemplate;
	}
}


@Slf4j
@RestController
public class TargetContoller {

	@GetMapping("/target")
	public String target(String key) {
		log.info("input key : {}", key);
		if (!StringUtils.equals("taetaetae", key)) {
			throw new RuntimeException("Invalid key");
		}
		return "target";
	}
}

์‚ฌ์‹ค ์„ค๋ช…ํ•  ๋ถ€๋ถ„๋„ ์—†๊ธด ํ•˜์ง€๋งŒ ๊ทธ๋ž˜๋„ ์ ์–ด๋ณด๋ฉด, /index๋ผ๋Š” ์ฃผ์†Œ์™€ key๋ผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์š”์ฒญ์„ ํ•˜๋ฉด /target์ด๋ผ๋Š” ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋ฐ›์•„์„œ key ๊ฐ’์— ๋”ฐ๋ผ ์ •์ƒ ์‘๋‹ต์„ ์ค„์ง€ ์•„๋‹ˆ๋ฉด ์—๋Ÿฌ๋ฅผ ์‘๋‹ตํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค. ๋ชฉํ‘œ๋กœ ํ•˜๋Š”๊ฑด, ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ผ๋ถ€๋Ÿฌ ์ž˜๋ชป์ค˜์„œ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒํ•˜๋Š”๋ฐ Hystrix๋ฅผ ์ ์šฉํ•ด์„œ ์„ค์ •ํ•œ ๊ธฐ์ค€์— ๋”ฐ๋ผ ์‘๋‹ต์€ ๋ฏธ๋ฆฌ ์ •ํ•ด๋‘” ์‘๋‹ต์„, TargetContoller์—์„œ๋Š” ์ž ์‹œ๋™์•ˆ ์š”์ฒญ์„ ๋ฐ›์ง€ ์•Š๋‹ค๊ฐ€ ์กฐ๊ธˆ์žˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๋ฉด ์š”์ฒญ์„ ๋ฐ›๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋กœ ์ž‘์„ฑํ•ด ๋ณด๋ ค ํ•œ๋‹ค. ์šฐ์„  ํ•„์š”ํ•œ dependency๋ฅผ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

๋งค๋‹ˆ์ €๋Š” ์ •๋ง ๊ฐœ๋ฐœ์ž์˜ ๋ฌด๋ค์ผ๊นŒ? (๋ฆฌ๋ทฐ - ๊ฐœ๋ฐœ์ž 7๋…„์ฐจ, ๋งค๋‹ˆ์ € 1์ผ์ฐจ)

๊ฐœ๋ฐœ์ž๋กœ์„œ์˜ ์ปค๋ฆฌ์–ด๋Š” ์ •๋ง ๋‹ค์–‘ํ•˜์ง€๋งŒ ํ•„์ž๊ฐ€ ๋ณด๊ณ  ๋“ค์€ ๊ฒฝํ—˜์„ ์•„์ฃผ ์ผ๋ฐ˜ํ™” ์‹œ์ผœ ์ •๋ฆฌํ•ด ๋ณด์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

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

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

/images/7-years-of-development-1st-day-of-manager/chiken.jpg
์š”๋ฆฌํ•˜๋Š” ๊ฑธ ์ข‹์•„ํ•˜์ง€๋งŒ ์ด์ƒํ•˜๊ฒŒ ์น˜ํ‚จ์ง‘์€ ํ•˜๊ณ  ์‹ถ์ง€ ์•Š๋‹ค.
์ถœ์ฒ˜ : https://catapult.tistory.com/entry/%EC%B9%98%ED%82%A8%EC%A7%91%EC%9D%B4%EB%82%98-%EC%B0%A8%EB%A0%A4%EC%95%BC%EC%A7%80

์–ด๋А ๋‚  SNS ํ”ผ๋“œ์— ๊ฐœ๋ฐœ ๊ด€๋ จ๋œ ์†Œ์‹๋“ค์„ ๋ฐ›์•„๋ณด๋‹ค๊ฐ€ ๊ฐœ๋ฐœ 7๋…„์ฐจ. ๋งค๋‹ˆ์ € 1์ผ์ฐจ๋ผ๋Š” ์ œ๋ชฉ์˜ ์ฑ…์„ ๋ณด๊ฒŒ ๋œ๋‹ค. ๋ญ์•ผ, ์ด๊ฑฐ ๋‚ด ์ด์•ผ๊ธฐ ์•„๋‹ˆ์•ผ? ํ•˜๋ฉฐ ๊ท€์‹ ์— ํ™€๋ฆฐ ๋“ฏ ์‚ฌ์„œ ์ฝ์–ด๋ณด๋ ค๋Š” ์ฐฐ๋‚˜, ๋งˆ์นจ ํ•œ๋น›๋ฏธ๋””์–ด ์—์„œ ์ฃผ์ตœํ•˜๋Š” ๋‚˜๋Š” ๋ฆฌ๋ทฐ์–ด๋‹ค ๋ผ๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ๊ฒฌํ•˜๊ฒŒ ๋œ๋‹ค. ๊ฒฐ๊ตญ ๋ฆฌ๋ทฐ์–ด์— ๋‹น์ฒจ์ด ๋˜๊ณ  ์šด ์ข‹๊ฒŒ ํ•ด๋‹น ์ฑ…์„ ๋ฐ›์•„๋ณผ ์ˆ˜ ์žˆ์—ˆ๋‹ค. (์ด ์ฑ…์„ ์ฝ๊ฒŒ ํ•ด์ค€ ํ•œ๋น›๋ฏธ๋””์–ด ์ธก์—๊ฒŒ ์ด ๊ธ€๋กœ๋‚˜๋งˆ ๊ฐ์‚ฌ์˜ ์ธ์‚ฌ๋ฅผ ์ „ํ•˜๊ณ  ์‹ถ๋‹ค.)

/images/7-years-of-development-1st-day-of-manager/book.jpg
ํ•„์ž์˜ SNS๋ฅผ ์žฅ์‹ํ–ˆ๋˜ ‘๊ฐœ๋ฐœ 7๋…„์ฐจ, ๋งค๋‹ˆ์ € 1์ผ์ฐจ’

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

์‹ ์ž… ํ˜น์€ ์ฃผ๋‹ˆ์–ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฝ์–ด๋ด๋„ ์ข‹์„ ์ฑ….

์ œ๋ชฉ๋งŒ ๋ณด๋ฉด ์ด์ œ ๊ฐ“ ํŒ€์žฅ ํ˜น์€ ๋งค๋‹ˆ์ €๋ฅผ ํ•˜๊ฒŒ ๋˜๋Š” ์‚ฌ๋žŒ์—๊ฒŒ๋งŒ ํ•ด๋‹น๋˜๋Š” ์ฑ…์œผ๋กœ ๋ณด์ธ๋‹ค. ํ‘œ์ง€ ์ƒ๋‹จ์— “๊ฐœ๋ฐœ๋งŒ ํ•ด์™”๋˜ ๋‚ด๊ฐ€, ์–ด๋А ๋‚  ๊ฐ‘์ž๊ธฐ ‘ํŒ€’์„ ๋งก์•˜๋‹ค!” ์ ํ˜€์žˆ๊ธฐ๋„ ํ–ˆ์œผ๋‹ˆ๊นŒ. ํ•˜์ง€๋งŒ ์ฑ…์„ ์ฝ๋‹ค ๋ณด๋ฉด ๊ผญ ๊ทธ๋ ‡์ง€๋งˆ๋Š” ์•Š๋‹ค. ๋ฉ˜ํ† ๋ง์„ ํ•  ๋•Œ์—” ๋ฉ˜ํ† ์™€ ๋ฉ˜ํ‹ฐ ๊ฐ์ž์˜ ์œ„์น˜์—์„œ ์–ด๋–ค ์ž์„ธ๋กœ ์„œ๋กœ๋ฅผ ๋งž์ดํ•ด์•ผ ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ๋„ ์•Œ๋ ค์ฃผ๊ธฐ๋„ ํ•˜๊ณ  ๋ฌด์ž‘์ • ๋ˆˆ์•ž์— ์žˆ๋Š” ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ๋งŒ์„ ํ•˜๋ฉฐ ์•ˆ๊ฐฏ์†์„ ๊ฑท๋Š” ์ฃผ๋‹ˆ์–ด ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฏธ๋ฆฌ ๋ฏธ๋ž˜๋ฅผ ๊ฒฝํ—˜ํ•ด๋ณด๋Š” ์ข‹์€ ์‚ฌ๋ก€๋ฅผ ๋“ค์–ด ์•Œ๋ ค์ฃผ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

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

๋‹ค ์ฝ๊ณ ์„œ์•ผ ์•Œ์•„์ฐจ๋ฆฐ ๋ฒˆ์—ญ์„œ(?)๋ผ๋Š” ์‚ฌ์‹ค.

์–ด๋– ํ•œ XX ๊ธฐ์ˆ  ์„œ์ ์—์„œ๋Š” Method๋ฅผ ‘๋ฐฉ๋ฒ•’, Overriding ์„ ‘๊ณผ์ ’์ด๋ผ๊ณ  ๋ฒˆ์—ญํ•œ ์ฑ…๋“ค์ด ์žˆ๋Š”๊ฐ€ ๋ฐ˜๋ฉด, ์ด ์ฑ…์€ ์ฝ๋Š” ๋‚ด๋‚ด ๊ตญ๋‚ด ์–ด๋–ค ๋ถ„์ด ์“ฐ์‹  ๊ฑฐ๋ผ ์ƒ๊ฐํ•˜๊ณ  ์ฝ์–ด๋‚ด๋ ค ๊ฐ”์ง€๋งŒ ๋‹ค ์ฝ๊ณ  ๋ณด๋‹ˆ ์™ธ๊ตญ์— ์–ด๋А CTO๊ฐ€ ์“ด ์ฑ…์„ ์˜ฎ๊ฒจ์„œ ๋‹ค์‹œ ์จ์ง„ ์ฑ…์ด์—ˆ๋‹ค. ๊ทธ๋งŒํผ ์ „ํ˜€ ํŠน์œ ์˜ ๋ฒˆ์—ญ ๋А๋‚Œ(?)์€ ์—†์—ˆ๊ณ  ์˜คํžˆ๋ ค ํ•œ๊ตญ ๋ฌธํ™”์— ๋งž์ถฐ ๋‹ค์‹œ ์จ์ง„ ๊ฑด ์•„๋‹๊นŒ ์‹ถ์„ ์ •๋„๋กœ ๋„ˆ๋ฌด ์ˆ ์ˆ  ์ž˜ ์ฝํ˜”๋‹ค.

์กฐ๊ธˆ ๋” ๊ดœ์ฐฎ์€ Rest Template 1๋ถ€ - Retryable

์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๋ฉด์„œ ๊ผญ ํ•œ๋ฒˆ ์ฏค ๋งŒ๋‚˜๊ฒŒ ๋˜๋Š” “RestTemplate”. ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์™ธ๋ถ€ HTTP URL(๋ณดํ†ต API)์„ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์ค‘์— ํ•˜๋‚˜๋กœ springframework ์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” ๋ชจ๋“ˆ์ด๋‹ค. ํŠนํžˆ ํฐ ํ•œ๋ฉ์–ด๋ฆฌ๋กœ ๊ด€๋ฆฌ๋˜๋˜ Monolithic Architecture ์—์„œ ์š”์ฒญ์„ ํ•˜๊ณ (client) ์‘๋‹ต์„ ์ฃผ๋Š”(server) ์ฆ‰, Endpoint๊ฐ€ ์ž‘์€ ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌ๋˜๋Š” Microservice Architecture ๋กœ ๋ฐ”๋€Œ๋ฉด์„œ ๊ฐ ์„œ๋น„์Šค๊ฐ„ ํ˜ธ์ถœ๋ฐฉ์‹์ด HTTP ์ผ ๊ฒฝ์šฐ ์ž์ฃผ ์‚ฌ์šฉ๋˜๊ณค ํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค. (webClient ๋“ฑ ๋‹ค๋ฅธ ์—ฌ๋Ÿฌ ํ˜ธ์ถœ ๋ฐฉ๋ฒ•๋“ค์ด ์žˆ๋‹ค.) ๋งŒ์•ฝ, ์š”์ฒญ์„ ํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ์ž…์žฅ์—์„œ ์‘๋‹ต์„ ์ฃผ๋Š” ์„œ๋ฒ„์˜ ์ƒํƒœ๊ฐ€ ๋ถˆ์•ˆ์ • ํ•˜๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„๋•Œ, ์–ด๋–ค์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ• ๊นŒ? ์˜ˆ์ปจ๋Œ€, ์š”์ฒญ 10๋ฒˆ์— ํ•œ๋ฒˆ์€ ์–ด๋– ํ•œ ์ด์Šˆ๋กœ ์‘๋‹ต์ด ์ง€์—ฐ๋˜๊ฑฐ๋‚˜ ์„œ๋ฒ„์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๊ณ  ํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ๋Š” ๊ฐ„ํ—์ ์ธ ์˜ค๋ฅ˜์‘๋‹ต์— ๋‹ต๋‹ตํ•จ์„ ํ˜ธ์†Œํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๊ทธ๋Ÿผ ์ž ์‹œ ๋ˆˆ์„ ๊ฐ๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž. ๊ฐ€๋ณ๊ฒŒ ์ƒ๊ฐํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ์•„์ฃผ ๊ฐ„๋‹จํ•˜๊ฒŒ “์˜ˆ์™ธ์ฒ˜๋ฆฌ"๋ฅผ ์ด์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

try {
	// http call
} catch (Exception e){
	// ์„œ๋ฒ„์—๋Ÿฌ๊ฐ€ ์•„๋‹Œ ์•ฝ์†๋œ ์—๋Ÿฌ์‘๋‹ต์„ ๋ฆฌํ„ด
}

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

/images/better-rest-template-1-retryable/retry.png
์‹ค์ œ๋กœ ์กฐ๊ธˆ์žˆ๋‹ค ํ•ด๋ณด๋ฉด ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์œผ๋‹ˆ ์•ˆ๋ ๋•Œ๋Š” ์กฐ๊ธˆ (์ฒœ์ฒœํžˆ) ์‹œ๋„ํ•ด๋ณด์ž.
์ถœ์ฒ˜ : http://www.segye.com/newsView/20200302504384

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” RestTemplate ๋ฅผ ์ด์šฉํ• ๋•Œ “์žฌ์‹œ๋„” ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ณ ์ž ํ•œ๋‹ค. ์•„์ฃผ ๊ฐ„๋‹จํ• ์ง€ ๋ชจ๋ฅด์ง€๋งŒ ๋…ธ๋ ฅ์— ๋น„ํ•ด ํšจ๊ณผ๊ฐ€ ์ƒ๋‹นํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ •๋ฆฌํ•ด ๋‘๊ณ  ์‹ถ์—ˆ๋‹ค.

Spring Retry

๊ณต์‹ Github์— ์†Œ๊ฐœ๋ฅผ ๋นŒ๋ฆฌ์ž๋ฉด, Spring ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•œ ์žฌ์‹œ๋„ ์ง€์›์„ ์ œ๊ณตํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. ์œ„์—์„œ ์ด์•ผ๊ธฐ ํ–ˆ๋˜ “RestTemplate"๊ณผ๋Š” ์‚ฌ์‹ค ๋ฌด๊ด€ํ•˜๊ณ , ์ด๋ฅผ ํ™œ์šฉํ•ด์„œ ์žฌ์‹œ๋„ ํ•˜๋Š” “RetryRestTemplate"๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด๋ ค ํ•˜๋Š”๊ฒƒ์ด๋‹ค. ์šฐ์„  ์ด “Spring-Retry"์˜ ์˜ˆ์ œ๋ฅผ ๋ณด๋ฉด ์•„์ฃผ ์‹ฌํ”Œํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์šฐ์„  pom์— ๊ตฌํ˜„์— ํ•„์š”ํ•œ dependency ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ๋ณด์ž.

<dependency>
	<groupId>org.springframework.retry</groupId>
	<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@Configuration
@EnableRetry // 1
public class Application {

    @Bean
    public Service service() {
        return new Service();
    }

}

@Service
class Service {
    @Retryable(RemoteAccessException.class) // 2
    public void service() {
        // ... do something
    }
    @Recover // 3
    public void recover(RemoteAccessException e) {
       // ... panic
    }
}
  1. @EnableRetry ์–ด๋…ธํ…Œ์ด์…˜์„ @Configuration์„ ์ง€์ •ํ•œ ํด๋ž˜์Šค ์ค‘ ํ•˜๋‚˜์— ์ถ”๊ฐ€ํ•œ๋‹ค.
  2. ์žฌ์‹œ๋„ ํ•˜๋ ค๋Š” ๋ฉ”์†Œ๋“œ์— @Retryable ์–ด๋…ธํ…Œ์ด์…˜์„ ์ง€์ •ํ•ด์ค€๋‹ค.
  3. ์žฌ์‹œ๋„๊ฐ€ ์™„๋ฃŒ๋˜๋Š” ์‹œ์ ์—์„œ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์„๋•Œ ์„ ์–ธํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜, @Retryable ๋™์ผํ•œ ํด๋ž˜์Šค์—์„œ ์„ ์–ธ๋˜์–ด์•ผ ํ•˜๊ณ  return type ์€ @Retryable์„ ์ง€์ •ํ•œ ๋ฉ”์†Œ๋“œ์™€ ๋™์ผํ•ด์•ผ ํ•œ๋‹ค.

Retry Rest Template

์ด๋ ‡๊ฒŒ springframework ์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” spring-retry ๋ฅผ ์ด์šฉํ•ด์„œ ์ด๋ฒˆ ํฌ์ŠคํŒ…์˜ ๋ชฉํ‘œ์ธ ์žฌ์‹œ๋„๋ฅผ ํ•˜๋Š” Retry Rest Template ๋ฅผ ๊ตฌ์„ฑํ•ด๋ณด์ž. ์šฐ์„ , RestTemplate ๋ฅผ Bean ์œผ๋กœ ๋“ฑ๋กํ•˜๊ณ , ์œ„์—์„œ ์ด์•ผ๊ธฐ ํ•œ ์–ด๋…ธํ…Œ์ด์…˜๋“ค๋กœ ๊ตฌ์„ฑํ•ด๋ณด์ž.

@EnableRetry
@Configuration
public class RetryableRestTemplateConfiguration {

	@Bean
	public RestTemplate retryableRestTemplate() {
		SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory(); // 1
		clientHttpRequestFactory.setReadTimeout(2000);
		clientHttpRequestFactory.setConnectTimeout(500);

		RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory) {
			@Override
			@Retryable(value = RestClientException.class, maxAttempts = 3, backoff = @Backoff(delay = 1000)) // 2
			public <T> ResponseEntity<T> exchange(URI url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType)
				throws RestClientException {
				return super.exchange(url, method, requestEntity, responseType); 
			}

			@Recover
			public <T> ResponseEntity<String> exchangeRecover(RestClientException e) {
				return ResponseEntity.badRequest().body("bad request T.T"); // 3
			}
		};

		return restTemplate;
	}
}
  1. SimpleClientHttpRequestFactory ๋ฅผ ๋งŒ๋“ค๊ณ  ๊ฐ ํƒ€์ž„์•„์›ƒ์„ ์„ค์ •ํ•ด์ค€ ๋‹ค์Œ RestTemplate ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒจ์ค€๋‹ค.
  2. ์‚ฌ์šฉํ•˜๋Š” ๊ณณ์—์„œ exchange ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•  ๊ฒƒ์ด๋ฏ€๋กœ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•ด์ค€๋‹ค. ๋จผ์ € ํ•ด๋‹น ๋ฉ”์†Œ๋“œ์—์„œ “RestClientException"์ด ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ Retry ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•œ๋‹ค๊ณ  ์ •ํ•ด์ฃผ๊ณ , ์ตœ๋Œ€ ์‹œ๋„๋Š” 3๋ฒˆ, backoff ์„ค์ •์ค‘ delay๋ฅผ 1000ms(1์ดˆ)๋กœ ์ง€์ •ํ•ด์„œ ์žฌ์‹œ๋„๊ฐ€ ์ง„ํ–‰๋˜๋„๋ก ํ•ด์ค€๋‹ค.
  3. 2 ์—์„œ ์ง€์ •ํ•œ ์žฌ์‹œ๋„๊ฐ€ ๋๋‚˜๋ฉด (์žฌ์‹œ๋„๋ฅผ ์ „๋ถ€ ๋‹ค ํ•˜๋ฉด) ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋˜์–ด์žˆ๊ณ , ์ž„์˜๋กœ ์‘๋‹ต์— ์ง€์ •ํ•œ ๋ฌธ๊ตฌ๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๊ณ  ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋กœ์ง์—์„œ ์ผ๋ถ€๋Ÿฌ ์ž˜๋ชป๋œ URL์„ ํ˜ธ์ถœํ•ด ๋ณด๋„๋ก ํ•˜์ž. ๊ทธ๋ฆฌ๊ณ ์„œ ๋กœ๊ทธ๋ฅผ ์ž์„ธํžˆ ๋ณด๋„๋ก application.properties ์— “debug=true” ์„ค์ •์„ ํ•ด์ค€๋‹ค.