[Spring ์‹ฌํ™”] ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง ๊ณผ์ œ ํšŒ๊ณ 

2025. 4. 18. 20:16ยท๋‚ด์ผ๋ฐฐ์›€์บ ํ”„/๋ณธ์บ ํ”„ ๊ณผ์ œ

์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง ๊ณผ์ œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด์„œ ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

๐Ÿ”Ž ํ•™์Šตํ•œ ๋‚ด์šฉ

1. Early return

์กฐ๊ฑด์— ๋งž์ง€์•Š๋Š” ๊ฒฝ์šฐ, ๋น ๋ฅด๊ฒŒ returnํ•˜๊ฑฐ๋‚˜ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ๋ถˆํ•„์š”ํ•œ ๋กœ์ง์ด ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์„ฑ๋Šฅ ํ–ฅ์ƒ, ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ๋†’์ด๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

ex) ํšŒ์›๊ฐ€์ž… ์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ encode ํ›„ email์ด ์œ ํšจํ•œ์ง€ ์ฐพ๋Š”๋‹ค๋ฉด, email์ด ์œ ํšจํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ encodeํ•œ ํ–‰์œ„๋Š” ๋ฌด์˜๋ฏธํ•œ ๋™์ž‘์ด ๋˜์–ด๋ฒ„๋ฆฐ๋‹ค. ๋•Œ๋ฌธ์—, email์ด ์œ ํšจํ•œ์ง€ ํ™•์ธํ•˜๊ณ , ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ encode ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ์„ค๊ณ„ํ•ด์•ผํ•œ๋‹ค.

 

2. ๋ถˆํ•„์š”ํ•œ if-else๋ฌธ ํ”ผํ•˜๊ธฐ

์ค‘์ฒฉ๋œ if-else๋ฌธ์„ ์ค„์—ฌ์„œ ์ฝ”๋“œ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•œ๋‹ค.

์ด๋ฅผ Arrowhead ๋ฅผ Guard Clause ์Šคํƒ€์ผ๋กœ ๊ฐœ์„ ํ•œ๋‹ค ๋ผ๊ณ  ํ‘œํ˜„ํ•œ๋‹ค. (์ถœ์ฒ˜: ์ต๋ช…์˜ ํŠœํ„ฐ๋‹˜)

์™œ ํ™”์‚ด์ด‰์ธ๊ฐ€ ํ–ˆ๋”๋‹ˆ..

์‚ฌ์ง„์ถœ์ฒ˜:  https://nus-cs2103-ay1920s1.github.io/website/se-book-adapted/chapters-printable/codeQuality-printable.html

๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ๋ช…ํ™•ํ•œ ์‚ฌ์ง„!

์ฝ”๋“œ๋กœ ๋ณด์ž๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

// Before๐Ÿคจ
if (!HttpStatus.OK.equals(response.getStatusCode())) {
    throw new ServerException(...);
} else {
    if (weatherArray == null || weatherArray.length == 0) {
        throw new ServerException(...);
    }
}


// After๐Ÿค—
if (!HttpStatus.OK.equals(response.getStatusCode())) {
    throw new ServerException(...);
}
if (weatherArray == null || weatherArray.length == 0) {
    throw new ServerException(...);
}

๊ตณ์ด ๋‹ค๋ฅธ ์กฐ๊ฑด๋ฌธ์„ ๋น„๊ตํ•  ๊ฑด๋ฐ if-else๋ฌธ์„ ์“ธ ํ•„์š”๊ฐ€ ์—†์—ˆ๋‹ค. 

์•„๋ฌด์ƒ๊ฐ ์—†์—ˆ๋Š”๋ฐ ์—ญ์‹œ ์•„๋ฌด์ƒ๊ฐ ์—†์œผ๋ฉด ์•ˆ๋œ๋‹ค.

์ง€๊ธˆ์€ ์งง์€ ์ฝ”๋“œ์ง€๋งŒ ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์ง€๋ฉด ๊ฐ€๋…์„ฑ์— ํ™•์—ฐํ•˜๊ฒŒ ์ฐจ์ด๊ฐ€ ๋‚  ๊ฒƒ ๊ฐ™๋‹ค.

 

3. DTO Validation์œผ๋กœ ์ฑ…์ž„ ์ด์ „ํ•˜๊ธฐ

๊ธฐ์กด์—๋Š” Service ๊ณ„์ธต์—์„œ if๋ฌธ์œผ๋กœ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ–ˆ์ง€๋งŒ, DTO์—์„œ ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ Validation์œผ๋กœ ๊ฒ€์ฆํ•œ๋‹ค.

์„œ๋น„์Šค์—๋Š” ๊ฒ€์ฆ๋œ ๊ฐ’๋งŒ ๋“ค์–ด์˜ค๋ฏ€๋กœ ๋กœ์ง์ด ๊ฐ„๊ฒฐํ•ด์ง„๋‹ค.

์‚ฌ์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” org.springframework.boot:spring-boot-starter-validation

๋™์ผํ•œ ์ด๋ฆ„์ด ์žˆ์œผ๋‹ˆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊นŒ์ง€ ์˜์‹ํ•ด์„œ ๊ณต๋ถ€ํ•ด์•ผํ•œ๋‹ค... 

 

4. N+1 ๋ฌธ์ œ

โœ”๏ธ N+1 ๋ฌธ์ œ๋ž€?

N๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ, ์—ฐ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ง€์—ฐ ๋กœ๋”ฉ(LAZY)์œผ๋กœ ๊ฐ€์ ธ์˜ค๋ฉฐ ์ถ”๊ฐ€๋กœ N๊ฐœ์˜ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ํ˜„์ƒ์ด๋‹ค.

์˜ˆ์‹œ๋ฅผ ๋“ค์ž๋ฉด,

1. ๊ฒŒ์‹œ๊ธ€ 10๊ฐœ ์กฐํšŒ → ์ฟผ๋ฆฌ 1๋ฒˆ ์‹คํ–‰ (SELECT * FROM posts)

2. ๊ฐ ๊ฒŒ์‹œ๊ธ€์˜ ์ž‘์„ฑ์ž(User)๋ฅผ ์กฐํšŒ → ๊ฒŒ์‹œ๊ธ€ ์ˆ˜๋งŒํผ ์ฟผ๋ฆฌ ์‹คํ–‰๋จ (N๋ฒˆ)
   SELECT * FROM users WHERE id = ?
   ...์ด๊ฒŒ 10๋ฒˆ ์‹คํ–‰๋จ ๐Ÿ˜จ

์ฆ‰ ์ด 1+N ๋ฒˆ์˜ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด๋‹ค...

์ฒ˜์Œ์—๋Š” ์ „์ฒด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” 1๊ฐœ์˜ ์ฟผ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋œ ๊ฒƒ์ด๋ผ ์ƒ๊ฐํ–ˆ๋Š”๋ฐ, ์—ฐ๊ด€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ N๋ฒˆ์ด ์ถ”๊ฐ€๋กœ ๋ถˆ๋Ÿฌ์˜ค๊ฒŒ ๋˜๋Š”๊ฒƒ์ด์—ˆ๋‹ค. 1์ด ์ถ”๊ฐ€์ธ ์ค„ ์•Œ๊ณ  ํฐ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋Š”๋ฐ N์ด ์ถ”๊ฐ€๋ผ๋‹ˆ.. ์•„์ฃผ ํฐ ๋ฌธ์ œ์˜€๋‹ค.

 

๐ŸŒ€ ๋‹จ์ 

์ฟผ๋ฆฌ๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์ด ์‹คํ–‰๋˜์–ด์„œ ์„ฑ๋Šฅ์ด ๋–จ์–ด์ง€๊ณ , ์„œ๋ฒ„ ๋ถ€ํ•˜๊ฐ€ ์ปค์ง„๋‹ค.

ํŠนํžˆ ๊ฒŒ์‹œ๊ธ€ ์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๋ฉด N์ด ์—„์ฒญ ์ปค์ง€๊ฒŒ ๋œ๋‹ค → ๊ทธ๋งŒํผ ๋А๋ ค์ง„๋‹ค.

 

๐Ÿš€ ํ•ด๊ฒฐ๋ฒ•

โœ”๏ธ fetch join

@Query("SELECT p FROM Post p JOIN FETCH p.user")
List<Post> findAllWithUser();

๊ฒŒ์‹œ๊ธ€(p)๊ณผ ์ž‘์„ฑ์ž(p.user)๋ฅผ ํ•œ ๋ฒˆ์˜ ์ฟผ๋ฆฌ๋กœ ๋ฌถ์–ด์„œ ๊ฐ€์ ธ์˜จ๋‹ค.

 

โœ”๏ธ @EntityGraph

@EntityGraph(attributePaths = {"user"})
List<Post> findAll();

์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ์— ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•จ๊ป˜ ๊ฐ€์ ธ์˜ค๋ผ๊ณ  ๋ช…์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

fetch join๊ณผ ์œ ์‚ฌํ•œ ํšจ๊ณผ์ง€๋งŒ ์ข€ ๋” ๋ช…ํ™•ํ•˜๋‹ค.

 

๐Ÿ’€ ๋ฐœ์ƒ ์›์ธ

์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์ง€์—ฐ๋กœ๋”ฉ์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ฒŒ์‹œ๊ธ€ ๋จผ์ € ๋ถˆ๋Ÿฌ์˜ค๊ณ , ์ž‘์„ฑ์ž๋Š” ๋‚˜์ค‘์— ํ•„์š”ํ• ๋•Œ ๋” ๋ถˆ๋Ÿฌ์˜ฌ๊ฒŒ์š”~ ๋ผ๊ณ  ์„ค์ •ํ•ด์„œ N๊ฐœ์˜ ์ฟผ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด์˜€๋‹ค.

 

์†”์งํ•˜๊ฒŒ ๋งํ•˜์ž๋ฉด.. ์•„์ง ์ง€์—ฐ๋กœ๋”ฉ์ด ๋ญ”์ง€ ๋ชจ๋ฅด๊ฒ ๊ณ  ๊ทธ๋ž˜์„œ fetch join, @EntityGraph ์–ด๋–ป๊ฒŒ ์“ฐ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ๋‹ค. ์ด๊ฑด ๋ณ„๋„์˜ ๊ฒŒ์‹œ๊ธ€๋กœ ์ •๋ฆฌ๋ฅผ ํ•˜๋ฉด์„œ ๊ณต๋ถ€๋ฅผ ํ•ด์•ผํ•œ๋‹ค ใ… .ใ…  

 

ํ™•์‹คํžˆ ์•Œ๊ฒŒ๋œ ํ•œ์ค„ ์š”์•ฝ์€ N+1 ๋ฌธ์ œ์˜ ํ•ด๊ฒฐ๋ฒ•์€ ์—ฐ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ๋ฒˆ์— ๊ฐ€์ ธ์™€์„œ ์ฟผ๋ฆฌ์ˆ˜๋ฅผ ์ค„์—ฌ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

 

5. ํ…Œ์ŠคํŠธ์ฝ”๋“œ

ํ•˜๋‚˜๋„ ๋ชจ๋ฅด๊ฒ ๋‹ค. ๊ณผ์ œ์—์„œ ๋ณด์—ฌ์ค€ ์‹คํŒจ ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ๋ฉ”์„œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ˆœ์„œ๋ฅผ ์ž˜๋ชป ๋„ฃ์Œ
  • Service ๊ณ„์ธต์—์„œ๋Š” A๋ผ๋Š” ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ–ˆ๋Š”๋ฐ, ํ…Œ์ŠคํŠธ์—์„œ๋Š” B๋ฅผ ๊ธฐ๋Œ€ํ–ˆ๋‹ค.
  • todo.getUser()๊ฐ€ null์ธ ์ƒํƒœ์—์„œ getId()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ, NPE๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

 

์˜ˆ์™ธ์ข…๋ฅ˜๋„ ๋” ๊ณต๋ถ€ํ•ด์•ผํ•œ๋‹ค. ์ด๋ฒˆ ๊ณผ์ œ์—์„œ ๊ณต๋ถ€ํ•œ ์˜ˆ์™ธ๋Š” ์•„๋ž˜ 2๊ฐœ..

  • InvalidRequestException: ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ž˜๋ชป๋œ ์š”์ฒญ์ด๋ผ๊ณ  ํŒ๋‹จํ•ด์„œ ์˜๋„์ ์œผ๋กœ ๋˜์ง€๋Š” ์˜ˆ์™ธ
  • NullPointerException: null์ธ ๊ฐ์ฒด์— ์ ‘๊ทผํ–ˆ์„ ๋•Œ ์ž๋ฐ”๊ฐ€ ์ž๋™์œผ๋กœ ํ„ฐ๋œจ๋ฆฌ๋Š” ์˜ˆ์™ธ, ์‚ฌ์ „์— null ์ฒดํฌ ํ•„์š”

 

์œ ๋‹› ํ…Œ์ŠคํŠธ์™€ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ

  • ์œ ๋‹› ํ…Œ์ŠคํŠธ: ๋ฉ”์„œ๋“œ ํ•˜๋‚˜๋งŒ ๋…๋ฆฝ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ
  • ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ: ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋œ ์ƒํƒœ(ex: ์ปจํŠธ๋กค๋Ÿฌ ์ „์ฒด)

 

ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ๊ตฌ์กฐ๋Š” given-when-then ํŒจํ„ด์„ ๋”ฐ๋ฅด๋‹ค. (์ค€๋น„-์‹คํ–‰-๊ฒ€์ฆ)

 

@ExtendWith, @InjectMocks  ์ด๋Ÿฐ ์ฒ˜์Œ๋ณด๋Š” ์–ด๋…ธํ…Œ์ด์…˜๋“ค.. ์„ธ์…˜ ๋ณต์Šต๊ณผ ์‹ค์Šต์ด ํ•„์š”ํ•˜๋‹ค๐Ÿ˜ญ

 

โœ๏ธ ๋А๋‚€์ 

๋ฆฌํŒฉํ† ๋ง ์ด๋ž€๊ฑธ ์ฒ˜์Œ ๊ฒฝํ—˜ํ•ด๋ณด์•˜๋‹ค.

ํด๋ฆฐ์ฝ”๋“œ, N+1 ๋ฌธ์ œ, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์— ๋Œ€ํ•œ ๊ณต๋ถ€๊ฐ€ ํ•„์š”ํ•˜๋‹ค. 

'๋‚ด์ผ๋ฐฐ์›€์บ ํ”„ > ๋ณธ์บ ํ”„ ๊ณผ์ œ' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

๋ฐฐ๋‹ฌ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์•„์›ƒ์†Œ์‹ฑ ํ”„๋กœ์ ํŠธ ํšŒ๊ณ   (3) 2025.04.29
[์ผ์ •๊ด€๋ฆฌ์•ฑ Develop-3] ์ผ์ •๊ด€๋ฆฌ์•ฑ Develop ๊ณผ์ œ ํšŒ๊ณ   (1) 2025.04.04
[์ผ์ •๊ด€๋ฆฌ์•ฑ Develop-2] ์ผ์ •๊ด€๋ฆฌ์•ฑ Develop ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…  (0) 2025.04.03
[์ผ์ •๊ด€๋ฆฌ์•ฑ Develop-1] ERD ๋ฐ API ๋ช…์„ธ์„œ ์ž‘์„ฑ  (0) 2025.04.02
[์ผ์ •๊ด€๋ฆฌ์•ฑ ๋งŒ๋“ค๊ธฐ-3] ์ผ์ •๊ด€๋ฆฌ์•ฑ ๊ณผ์ œ ํšŒ๊ณ   (1) 2025.03.26
'๋‚ด์ผ๋ฐฐ์›€์บ ํ”„/๋ณธ์บ ํ”„ ๊ณผ์ œ' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • ๋ฐฐ๋‹ฌ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์•„์›ƒ์†Œ์‹ฑ ํ”„๋กœ์ ํŠธ ํšŒ๊ณ 
  • [์ผ์ •๊ด€๋ฆฌ์•ฑ Develop-3] ์ผ์ •๊ด€๋ฆฌ์•ฑ Develop ๊ณผ์ œ ํšŒ๊ณ 
  • [์ผ์ •๊ด€๋ฆฌ์•ฑ Develop-2] ์ผ์ •๊ด€๋ฆฌ์•ฑ Develop ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…
  • [์ผ์ •๊ด€๋ฆฌ์•ฑ Develop-1] ERD ๋ฐ API ๋ช…์„ธ์„œ ์ž‘์„ฑ
aggeeeee
aggeeeee
ใ€€ φ(๏ผŽ๏ผŽ;)ใ€€๐Ÿ”œใ€€\_ใธ(โ–ญ-โ–ญ)โœจ
  • aggeeeee
    ๐Ÿฅ” ๋‹˜์˜ ๋ธ”๋กœ๊ทธ
    aggeeeee
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (155)
      • Today I Learned (25)
      • ๋‚ด์ผ๋ฐฐ์›€์บ ํ”„ (115)
        • ๋ณธ์บ ํ”„ ๊ณผ์ œ (17)
        • ์‚ฌ์ „์บ ํ”„ ๊ณผ์ œ (23)
        • SQL ์ฝ”๋“œ์นดํƒ€ (44)
        • ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ฝ”๋“œ์นดํƒ€ (31)
      • ๐Ÿ’ป๐Ÿš€ (15)
        • Java (7)
        • Git & GitHub (1)
        • CS (4)
        • Spring & SpringBoot (3)
  • ๋งํฌ

  • ์ตœ๊ทผ ๊ธ€

  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.3
aggeeeee
[Spring ์‹ฌํ™”] ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง ๊ณผ์ œ ํšŒ๊ณ 
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”