Chapter 5 - KOO-YS/toby-spring GitHub Wiki


์„œ๋น„์Šค ์ถ”์ƒํ™”


Goals

  • ์Šคํ”„๋ง์ด ์–ด๋–ป๊ฒŒ ์„ฑ๊ฒฉ์ด ๋น„์Šทํ•œ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ๊ธฐ์ˆ ์„ ์ถ”์ƒํ™”ํ•˜๊ณ  ์ด๋ฅผ ์ผ๊ด€๋œ ๋ฐฉ๋ฒ•์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด๊ธฐ

๐ŸŒฑ Branch chapter05 folder ์‚ฌ์šฉ


5.1 ์‚ฌ์šฉ์ž ๋ ˆ๋ฒจ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ ์ถ”๊ฐ€



๐ŸŒฑ Branch chapter05/refactor5.1์— ์‹ค์Šต ์ ์šฉ



  • ์˜๋„ : ์ •๊ธฐ์ ์œผ๋กœ ์‚ฌ์šฉ์ž์˜ ํ™œ๋™ ๋‚ด์—ญ์„ ์ฐธ๊ณ ํ•ด์„œ ๋ ˆ๋ฒจ์„ ์กฐ์ •ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ ์ถ”๊ฐ€

  • ์ฝ”๋“œ ๋ฐ˜์˜ : User ํด๋ž˜์Šค -> **์‚ฌ์šฉ์ž ๋ ˆ๋ฒจ ํ•„๋“œ [level : BASIC, SILVER, GOLD]**๋ฅผ ์ถ”๊ฐ€

    DB์— varchar ํƒ€์ž…์œผ๋กœ ์„ ์–ธํ•˜๊ณ  ๋ฌธ์žํ˜•์œผ๋กœ BASIC, SILVER, GOLD๋ฅผ ๋„ฃ์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ,

    ์ผ์ •ํ•œ ์ข…๋ฅ˜์˜ ์ •๋ณด๋Š” Enum์„ ์ด์šฉํ•˜๋Š”๊ฒŒ ์•ˆ์ „ํ•˜๋‹ค

    โ–ถ ์ด๋„˜ ํด๋ž˜์Šค ์ถ”๊ฐ€ ์™„๋ฃŒ

    public enum Level {
        BASIC(1), SILVER(2), GOLD(3);
    
        private final int value;
    
        Level(int value) {
            this.value = value; 	
            // DB์— ์ €์žฅํ•  int ํƒ€์ž…์˜ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€๋งŒ ๊ฒ‰์œผ๋กœ๋Š” Level ํƒ€์ž… ์˜ค๋ธŒ์ ํŠธ
        }
    
        // ...
    }

    โ–ถ DB ํ•„๋“œ ์ถ”๊ฐ€ ์™„๋ฃŒ : users ํ…Œ์ด๋ธ”์˜ ํ•„๋“œ ์ถ”๊ฐ€

๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค ๋กœ์ง๊ณผ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ์„œ๋กœ๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ์˜ํ–ฅ๋ฐ›์ง€ ์•Š๋„๋ก ํ•œ๋‹ค

โ–ถ UserService ํด๋ž˜์Šค ์ƒ์„ฑ


5.2 ํŠธ๋žœ์žญ์…˜ ์„œ๋น„์Šค ์ถ”์ƒํ™”



๐ŸŒฑ Branch chapter05/refactor5.2์— ์‹ค์Šต ์ ์šฉ



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

-> ๋’ค์— ์ฒ˜๋ฆฌ์— ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์•ž์˜ ์—…๊ทธ๋ ˆ์ด๋“œ๋Š” ๋Œ์•„๊ฐ€์ง€ ์•Š๋Š”๋‹ค

java.lang.AssertionError: 
Expected: is <BASIC>
     but: was <SILVER>

ํŠธ๋žœ์žญ์…˜

  • ๋” ์ด์ƒ ๋‚˜๋ˆŒ ์ˆ˜ ์—†๋Š” ๋‹จ์œ„ ์ž‘์—…

  • ์›์ž์„ฑ : ์ž‘์—…์„ ์ชผ๊ฐœ์„œ ์ž‘์€ ๋‹จ์œ„๋กœ ๋งŒ๋“ค ์ˆ˜ ์—†๋Š” ํŠธ๋žœ์žญ์…˜์˜ ํ•ต์‹ฌ ์†์„ฑ

  • ์ค‘๊ฐ„์— ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด์„œ ์ž‘์—…์„ ์™„๋ฃŒํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ์•„์˜ˆ ์ž‘์—…์ด ์‹œ์ž‘๋˜์ง€ ์•Š์€ ๊ฒƒ ์ฒ˜๋Ÿผ ์ดˆ๊ธฐ ์ƒํƒœ๋กœ ๋Œ๋ ค๋†”์•ผํ•œ๋‹ค


ํŠธ๋žœ์žญ์…˜ ๋กค๋ฐฑ : ๋‘ ๊ฐ€์ง€ ์ž‘์—…์ด ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์ด ๋  ๋•Œ, ๋‘ ๋ฒˆ์งธ SQL์ด ์ˆ˜ํ–‰ ์‹œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ, ์•ž์—์„œ ์ฒ˜๋ฆฌํ•œ SQL ์ž‘์—…๋„ ์ทจ์†Œ์‹œ์ผœ์•ผ ํ•œ๋‹ค

ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ : ์—ฌ๋Ÿฌ ๊ฐœ์˜ SQL์„ ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ์— ๋ชจ๋“  SQL ์ˆ˜ํ–‰ ์ž‘์—…์ด ๋‹ค ์„ฑ๊ณต์ ์œผ๋กœ ๋งˆ๋ฌด๋ฆฌ๋๋‹ค๊ณ  DB์— ์•Œ๋ ค์ค€ ํ›„ ์ž‘์—…์„ ํ™•์ •์ง€์Œ




ํŠธ๋žœ์žญ์…˜์ด ๋๋‚˜๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•

  • Rollback : ๋ชจ๋“  ์ž‘์—…์„ ๋ฌดํšจํ™”ํ•˜๋Š” ๋กค๋ฐฑ
  • Commit : ๋ชจ๋“  ์ž‘์—…์„ ๋‹ค ํ™•์ •ํ•˜๋Š” ์ปค๋ฐ‹

JDBC์˜ ํŠธ๋žœ์žญ์…˜

ํ•˜๋‚˜์˜ Connection์„ ๊ฐ€์ ธ์™€ ์‚ฌ์šฉํ•˜๋‹ค๊ฐ€ ๋‹ซ๋Š” ์‚ฌ์ด์—์„œ ์ผ์–ด๋‚จ

ํŠธ๋žœ์žญ์…˜์˜ ์‹œ์ž‘๊ณผ ์ข…๋ฃŒ๋Š” Connection ์˜ค๋ธŒ์ ํŠธ๋ฅผ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง„๋‹ค

Connection c = dataSource.getConnection();

c.setAutoCommit(false);		// ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘

// ...
// ...

c.commit();
// or
c.rollback();

โ–ถ setAutoCommit(false)๋กœ ํŠธ๋žœ์žญ์…˜์˜ ์‹œ์ž‘์„ ์„ ์–ธํ•˜๊ณ  commit() ๋˜๋Š” rollback()์œผ๋กœ ํŠธ๋žœ์žญ์…˜์„ ์ข…๋ฃŒํ•˜๋Š” ์ž‘์—…์„ **ํŠธ๋žœ์žญ์…˜์˜ ๊ฒฝ๊ณ„์„ค์ •(transaction demarcation)**์ด๋ผ๊ณ  ํ•œ๋‹ค


โ–ถ ๋กœ์ปฌ ํŠธ๋žœ์žญ์…˜ : ํ•˜๋‚˜์˜ DB ์ปค๋„ฅ์…˜ ์•ˆ์—์„œ ๋งŒ๋“ค์–ด์ง€๋Š” ํŠธ๋žœ์žญ์…˜

ํŠธ๋žœ์žญ์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ์ „ํ˜•์ ์ธ JDBC ์ฝ”๋“œ์˜ ๊ตฌ์กฐ
(1) DB Connection ์ƒ์„ฑ
(2) ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘
try{
    (3) DAO ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ
    (4) ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹
} catch(Exception e){
    (5) ํŠธ๋žœ์žญ์…˜ ๋กค๋ฐฑ
}finally {
    (6) DB Connection ์ข…๋ฃŒ
}



UserService ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„ ์„ค์ •์˜ ๋ฌธ์ œ์ 
  • UserService ๋ฉ”์†Œ๋“œ๋“ค์— Connection ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค? -> DAO๋ฅผ ํ•„์š”๋กœ ํ• ๋•Œ ๊ทธ ์‚ฌ์ด ๋ชจ๋“  ๋ฉ”์†Œ๋“œ์— ๊ฑธ์ณ์„œ Connection ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ๊ณ„์† ์ „๋‹ฌ๋ผ์•ผ ํ•œ๋‹ค
  • Connection ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ UserDao ์ธํ„ฐํŽ˜์ด์Šค ๋ฉ”์†Œ๋“œ์— ์ถ”๊ฐ€๋˜๋ฉด UserDao๋Š” ๋”์ด์ƒ ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค ๊ธฐ์ˆ ์— ๋…๋ฆฝ์ ์ผ ์ˆ˜๊ฐ€ ์—†๋‹ค๋Š” ์ 

์Šคํ”„๋ง์˜ ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋ฐฉ์‹(transaction synchronization)

  • UserService์—์„œ ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“  Connection ์˜ค๋ธŒ์ ํŠธ๋ฅผ ํŠน๋ณ„ํ•œ ์ €์žฅ์†Œ์— ๋ณด๊ด€ํ•ด๋‘๊ณ , ์ดํ›„์— ํ˜ธ์ถœ๋˜๋Š” DAO ๋ฉ”์†Œ๋“œ์—์„œ๋Š” ์ €์žฅ๋œ Connection์„ ๊ฐ€์ ธ๋‹ค๊ฐ€ ์‚ฌ์šฉํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ

  • ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ์ €์žฅ์†Œ๋Š” ์ž‘์—… ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๋…๋ฆฝ์ ์œผ๋กœ Connection ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์ค‘ ์‚ฌ์šฉ์ž๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์„œ๋ฒ„์˜ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋„ ์ถฉ๋Œ์ด ๋‚  ์—ผ๋ ค๊ฐ€ ์—†๋‹ค

  • ์Šคํ”„๋ง์€ JdbcTemplate๊ณผ ๋”๋ถˆ์–ด ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ฉ”์†Œ๋“œ๋ฅผ ์ œ๊ณต -> DataSourceUtils

  • TransactionSynchronizationManager : ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๊ด€๋ฆฌ ํด๋ž˜์Šค. ์ด ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•ด ๋จผ์ € ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ์ž‘์—…์„ ์ดˆ๊ธฐํ™”ํ•˜๋„๋ก ์š”์ฒญ

    public void upgradeLevels() throws SQLException {
        // ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋Š” ์Šคํ”„๋ง์˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ฉ”์†Œ๋“œ
        TransactionSynchronizationManager.initSynchronization();        // ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๊ด€๋ฆฌ์ž๋ฅผ ์ด์šฉํ•ด ๋™๊ธฐํ™” ์ž‘์—…์„ ์ดˆ๊ธฐํ™”
    
        Connection c = DataSourceUtils.getConnection(dataSource);       // DB ์ปค๋„ฅ์…˜ ์ƒ์„ฑ๊ณผ ๋™๊ธฐํ™”๋ฅผ ํ•จ๊ป˜ ํ•ด์ฃผ๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ฉ”์†Œ๋“œ
        c.setAutoCommit(false);         // DB ์ปค๋„ฅ์…˜์„ ์ƒ์„ฑํ•˜๊ณ  ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘
    
        // ์ดํ›„ DAO ์ž‘์—…์€ ๋ชจ๋‘ ์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์ง„ํ–‰๋œ๋‹ค
    
        try {
            List<User> users = userDao.getAll();
            for (User user : users) {
                if (canUpgradeLevel(user))       // ํ•œ ๋ช…์”ฉ ์—…๊ทธ๋ ˆ์ด๋“œ ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์ธ
                    upgradeLevel(user);         // ํ•œ ๋ช… ์—…๊ทธ๋ ˆ์ด๋“œ
            }
            c.commit();         // ์ •์ƒ ์ข…๋ฃŒ
        } catch (Exception e){
            c.rollback();       // ์˜ˆ์™ธ ๋ฐœ์ƒ -> ๋ฐ์ดํ„ฐ ๋˜๋Œ๋ฆฌ๊ธฐ
            throw e;
        } finally {
            DataSourceUtils.releaseConnection(c, dataSource);   // DB ์ปค๋„ฅ์…˜์„ ์•ˆ์ „ํ•˜๊ฒŒ ๋‹ซ๋Š”๋‹ค
            // ๋™๊ธฐํ™” ์ž‘์—… ์ข…๋ฃŒ ๋ฐ ์ •๋ฆฌ
            TransactionSynchronizationManager.unbindResource(this.dataSource);
            TransactionSynchronizationManager.clearSynchronization();
        }
    }

๊ธ€๋กœ๋ฒŒ ํŠธ๋žœ์žญ์…˜(global transaction)
  • ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ DB์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ๋Š” ์ž‘์—…์„ ํ•ด์•ผํ•  ํ•„์š” ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์‚ฌ์šฉ
  • ๋ณ„๋„์˜ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ์ž๋ฅผ ํ†ตํ•ด ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌ
  • ์ž๋ฐ”๋Š” JDBC ์™ธ์— ๊ธ€๋กœ๋ฒŒ ํŠธ๋žœ์žญ์…˜์„ ์ง€์›ํ•˜๋Š” ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €๋ฅผ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•œ API์ธ JTA(Java Transaction API)๋ฅผ ์ œ๊ณต

์Šคํ”„๋ง์˜ ํŠธ๋žœ์žญ์…˜ ์ถ”์ƒํ™” ๊ณ„์ธต

DB ํด๋ผ์ด์–ธํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด SQL์„ ์ด์šฉํ•˜๋Š” ๋ฐฉ์‹์˜ ๊ณตํ†ต์ ์„ ๋ฝ‘์•„๋‚ด ์ถ”์ƒํ™” ํ•œ JDBC ๋•๋ถ„์— DB ์ƒ๊ด€์—†์ด ์ผ๊ด€๋œ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฐ์ดํ„ฐ ์—‘์„ธ์Šค ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ ์ฝ”๋“œ์—๋„ ์ถ”์ƒํ™”๋ฅผ ๋„์ž…ํ•œ๋‹ค๋ฉด?

์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ํŠธ๋žœ์žญ์…˜ ์ถ”์ƒํ™” ๊ธฐ์ˆ ์„ ์ด์šฉํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ง์ ‘ ๊ฐ ๊ธฐ์ˆ ์˜ ํŠธ๋žœ์žญ์…˜ API๋ฅผ ์ด์šฉํ•˜์ง€ ์•Š๊ณ ๋„, ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ํŠธ๋žœ์žญ์…˜์„ ์ œ์–ดํ•˜๋Š” ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„ ์„ค์ • ์ž‘์—…์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค

5.3 ์„œ๋น„์Šค ์ถ”์ƒํ™”์™€ ๋‹จ์ผ ์ฑ…์ž„ ์›์น™


์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง์˜ ์ข…๋ฅ˜์— ๋”ฐ๋ฅธ ์ˆ˜ํ‰์  ๊ตฌ๋ถ„์ด๋“ ,

๋กœ์ง๊ณผ ๊ธฐ์ˆ ์ด๋ผ๋Š” ์ˆ˜์ง์ ์ธ ๊ตฌ๋ถ„์ด๋“ ,

๋ชจ๋‘ ๊ฒฐํ•ฉ๋„๊ฐ€ ๋‚ฎ์œผ๋ฉฐ ์„œ๋กœ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ์ž์œ ๋กญ๊ฒŒ ํ™•์žฅ๋  ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๋ฐ๋Š” ์Šคํ”„๋ง์˜ DI๊ฐ€ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•˜๊ณ  ์žˆ๋‹ค

์ด๋Ÿฌํ•œ ์ ์ ˆํ•œ ๋ถ„๋ฆฌ๊ฐ€ ๊ฐ€์ ธ์˜ค๋Š” ํŠน์ง•์€ ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„์˜ ์›์น™ ์ค‘์˜ ํ•˜๋‚˜์ธ ๋‹จ์ผ ์ฑ…์ž„ ์›์น™์œผ๋กœ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค


๋‹จ์ผ ์ฑ…์ž„ ์›์น™ (Single Responsibility Principle)

ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ์€ ํ•œ ๊ฐ€์ง€ ์ฑ…์ž„์„ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค.

ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ์ด ๋ฐ”๋€Œ๋Š” ์ด์œ ๋Š” ํ•œ ๊ฐ€์ง€์—ฌ์•ผ ํ•œ๋‹ค.


๋‹จ์ผ ์ฑ…์ž„ ์›์น™์˜ ์žฅ์ 

์–ด๋–ค ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•  ๋•Œ ์ˆ˜์ • ๋Œ€์ƒ์ด ๋ช…ํ™•ํ•ด์ง

๋‹จ์ผ ์ฑ…์ž„ ์›์น™์„ ์ž˜ ์ง€ํ‚ค๋Š” ์ฝ”๋“œ๋ฅผ ๋งŒ๋“œ๋ ค๋ฉด?

  • ์ธํ„ฐํŽ˜์ด์Šค ๋„์ž… ํ›„, DI๋กœ ์—ฐ๊ฒฐ

  • ๊ฐœ๋ฐฉ ํ์‡„ ์›์น™ ๋˜ํ•œ ์ค€์ˆ˜

  • ๋ชจ๋“ˆ ๊ฐ„์˜ ๊ฒฐํ•ฉ๋„๊ฐ€ ๋‚ฎ์•„์„œ ์„œ๋กœ์˜ ๋ณ€๊ฒฝ์ด ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Œ

  • ๋ณ€๊ฒฝ์ด ๋‹จ์ผ ์ฑ…์ž„์— ์ง‘์ค‘๋˜์–ด ์‘์ง‘๋„๊ฐ€ ๋†’์•„์•ผํ•จ


5.4 ๋ฉ”์ผ ์„œ๋น„์Šค ์ถ”์ƒํ™”



๐ŸŒฑ Branch chapter05/refactor5.4์— ์‹ค์Šต ์ ์šฉ



โ–ถ ๋ฉ”์ผ ์„œ๋น„์Šค๋ฅผ ์œ„ํ•œ Userํด๋ž˜์Šค์˜ ํ”„๋กœํผํ‹ฐ์™€ DB์— ์ปฌ๋Ÿผ ์ถ”๊ฐ€ ์™„๋ฃŒ

JavaMail

  • ์ž๋ฐ”์—์„œ ๋ฉ”์ผ์„ ๋ฐœ์†กํ•  ๋•Œ ํ‘œ์ค€ ๊ธฐ์ˆ 
  • javax.mail ํŒจํ‚ค์ง€์—์„œ ์ œ๊ณตํ•˜๋Š” ์ž๋ฐ”์˜ ์ด๋ฉ”์ผ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉ


  • ๋ฉ”์ผ ์ „์†ก ๋ฉ”์†Œ๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ๋งค๋ฒˆ ์‹ค์ œ ๋ฉ”์ผ์„ ๋ฐœ์†กํ•˜๋Š” ๊ฒƒ์€ ๋ถ€์ ํ•ฉ -> ์„œ๋ฒ„ ๋ถ€ํ•˜
    • ํ…Œ์ŠคํŠธ์šฉ ๋ฉ”์ผ ์„œ๋ฒ„๋ฅผ ์ด์šฉํ•˜์ž
  • ๋ฉ”์ผ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๋งค๋ฒˆ ๋ฉ”์ผ ์ˆ˜์‹  ์—ฌ๋ถ€๊นŒ์ง€ ์ผ์ผ์ด ํ™•์ธํ•˜๊ธฐ ๋ณด๋‹จ, ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ ๋ฉ”์ผ ์„œ๋ฒ„๊นŒ์ง€๋งŒ ์ž˜ ์ „์†ก๋˜๋Š”์ง€ ํ™•์ธํ•˜์ž

JavaMail์„ ์ด์šฉํ•œ ํ…Œ์ŠคํŠธ์˜ ๋ฌธ์ œ์ 

  • JavaMail์˜ API๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ–๋Š” ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค

    • Session ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด์•ผ๋งŒ ๋ฉ”์ผ ๋ฉ”์‹œ์ง€๋ฅผ ์ƒ์„ฑ, ์ „์†ก ๊ฐ€๋Šฅ -> Session์€ ํด๋ž˜์Šค๋‹ค..(์ธํ„ฐํŽ˜์ด์Šค X)

    • ์ƒ์„ฑ์ž๊ฐ€ ๋ชจ๋‘ private๋กœ ์„ ์–ธ๋˜์–ด ์žˆ์–ด์„œ ์ง์ ‘ ์ƒ์„ฑ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค

    • Session ํด๋ž˜์Šค๋Š” ๋” ์ด์ƒ ์ƒ์†์ด ๋ถˆ๊ฐ€๋Šฅํ•œ final ํด๋ž˜์Šค์ด๋‹ค

    • MailMessage(๋ฉ”์ผ ๋ฉ”์‹œ์ง€ ์ž‘์„ฑ), Transport(์ „์†ก)๋„ ๋งˆ์ฐฌ๊ฐ€์ง€..

      @Deprecated
      private void sendUpgradeEMail(User user) {
          Properties props = new Properties();
          props.put("mail.smtp.host", "mail.yaans.com");
          Session s = Session.getInstance(props, null);
      
          MimeMessage message = new MimeMessage(s);   // ๋ฉ”์ผ ๋ฉ”์‹œ์ง€ ์ž‘์„ฑ
          try {
              message.setFrom(new InternetAddress(TEMP_EMAIL));
              message.addRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail()));
      
              message.setSubject("Upgrade ์•ˆ๋‚ด");
              message.setText(user.getName()+" ์‚ฌ์šฉ์ž๋‹˜์˜ ๋“ฑ๊ธ‰์ด "+user.getLevel().name()+"๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค");
      
              Transport.send(message);                // ์ „์†ก
          } catch (AddressException e) {
              e.printStackTrace();
          } catch (MessagingException e) {
              e.printStackTrace();
          }
      }

Spring์—์„œ๋Š” JavaMail์— ๋Œ€ํ•œ ์ถ”์ƒํ™” ๊ธฐ๋Šฅ ์ œ๊ณต

MailSender Interface ์‚ฌ์šฉ : SimpleMailMessage ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค์— ๋‹ด๊ธด ๋ฉ”์ผ ๋ฉ”์‹œ์ง€ ์ „์†ก์„ ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋กœ ๊ตฌ์„ฑ

private void sendUpgradeEMail(User user){
    // (์Šคํ”„๋ง์ด ์žฌ๊ณตํ•˜๋Š” )JavaMail์„ ์‚ฌ์šฉํ•ด ๋ฉ”์ผ ๋ฐœ์†ก ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” JavaMailSenderImpl ํด๋ž˜์Šค
    JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
    mailSender.setHost("mail.server.com");

    SimpleMailMessage mailMessage = new SimpleMailMessage();

    mailMessage.setTo(user.getEmail());
    mailMessage.setFrom(TEMP_EMAIL);

    mailMessage.setSubject("Upgrade ์•ˆ๋‚ด");
    mailMessage.setText(user.getName()+" ์‚ฌ์šฉ์ž๋‹˜์˜ ๋“ฑ๊ธ‰์ด "+user.getLevel().name()+"๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค");

    mailSender.send(mailMessage);
}

JavaMail์ด ์•„๋‹Œ ๋‹ค๋ฅธ ๋ฉ”์‹œ์ง• ์„œ๋ฒ„์˜ API๋ฅผ ์ด์šฉํ•ด ๋ฉ”์ผ์„ ์ „์†กํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ฒจ๋„, ํ•ด๋‹น ๊ธฐ์ˆ ์˜ API๋ฅผ ์ด์šฉํ•˜์ง€ ์•Š๋Š” MailSender ๊ตฌํ˜„ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ DIํ•ด์ฃผ๋ฉด ๋œ๋‹ค

์˜์กด ์˜ค๋ธŒ์ ํŠธ์˜ ๋ณ€๊ฒฝ์„ ํ†ตํ•œ ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•

DummyMailSender๊ฐ€ ๋นˆ ํด๋ž˜์Šค์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋ฉ”์ผ ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ๋ฅผ ํ•จ์— ์žˆ์–ด์„œ ๊ต‰์žฅํžˆ ์œ ์šฉํ•˜๋‹ค.

์ด์ฒ˜๋Ÿผ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋ฒ• :

ํ…Œ์ŠคํŠธํ•  ๋Œ€์ƒ์ด ์˜์กดํ•˜๊ณ  ์žˆ๋Š” ์˜ค๋ธŒ์ ํŠธ๋ฅผ DI๋ฅผ ํ†ตํ•ด ๋ฐ”๊ฟ”์น˜๊ธฐ ํ•˜๋Š” ๊ฒƒ

ํ…Œ์ŠคํŠธ ๋Œ€์—ญ(test double)
  • ํ…Œ์ŠคํŠธ ๋Œ€์ƒ์ด ๋˜๋Š” ์˜ค๋ธŒ์ ํŠธ์˜ ๊ธฐ๋Šฅ์—๋งŒ ์ถฉ์‹คํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ•˜๋ฉด์„œ ๋น ๋ฅด๊ฒŒ, ์ž์ฃผ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์‚ฌ์šฉํ•˜๋Š” ์˜ค๋ธŒ์ ํŠธ๋ฅผ ํ†ต๋“ค์–ด์„œ ํ•˜๋Š” ๋ง

    • ex) UserServiceTest์˜ ๊ด€์‹ฌ์‚ฌ๋Š” UserService์—์„œ ๊ตฌํ˜„ํ•ด๋†“์€ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€๊ณตํ•˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด์ง€, ๋ฉ”์ผ์ด ์–ด๋–ป๊ฒŒ ์ „์†ก๋  ๊ฒƒ์ธ์ง€๊ฐ€ ์•„๋‹˜ -> ํ…Œ์ŠคํŠธ ์‹œ, DummyMailSender๋กœ ์ „ํ™˜ํ•ด์„œ ์‚ฌ์šฉ
  • ํ…Œ์ŠคํŠธ ์Šคํ…(test stub)

    • ๋Œ€ํ‘œ์ ์ธ ํ…Œ์ŠคํŠธ ๋Œ€์—ญ
    • ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ์˜ค๋ธŒ์ ํŠธ์˜ ์˜์กด๊ฐ์ฒด๋กœ์„œ ์กด์žฌ & ํ…Œ์ŠคํŠธ ๋™์•ˆ์— ์ฝ”๋“œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š” ๊ฒƒ
    • ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์ „๋‹ฌํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ๋‹ฌ๋ฆฌ, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋‚ด๋ถ€์—์„œ ๊ฐ„์ ‘์ ์œผ๋กœ ์‚ฌ์šฉ
    • DI ๋“ฑ์„ ํ†ตํ•ด ๋ฏธ๋ฆฌ ์˜์กด ์˜ค๋ธŒ์ ํŠธ๋ฅผ ํ…Œ์ŠคํŠธ ์Šคํ…์œผ๋กœ ๋ณ€๊ฒฝํ•ด์•ผํ•œ๋‹ค ex) DummyMailSender
  • ๋ชฉ ์˜ค๋ธŒ์ ํŠธ(mock object)

    • ํ…Œ์ŠคํŠธ ๋Œ€์ƒ์˜ ๊ฐ„์ ‘์ ์ธ ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์ฆํ•˜๊ณ , ํ…Œ์ŠคํŠธ ๋Œ€์ƒ ์˜ค๋ธŒ์ ํŠธ์™€ ์˜์กด ์˜ค๋ธŒ์ ํŠธ "์‚ฌ์ด"์—์„œ ์ผ์–ด๋‚˜๋Š” ์ผ์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋„๋ก **ํŠน๋ณ„ํ•˜๊ฒŒ ์„ค๊ณ„๋œ ์˜ค๋ธŒ์ ํŠธ **
    • ํ…Œ์ŠคํŠธ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋˜๋„๋ก ๋„์™€์ฃผ๋ฉด์„œ, ํ…Œ์ŠคํŠธ ์˜ค๋ธŒ์ ํŠธ์™€ ์ž์‹ ์˜ ์‚ฌ์ด์—์„œ ์ผ์–ด๋‚˜๋Š” ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜ ๋‚ด์šฉ์„ ์ €์žฅํ•ด๋’€๋‹ค๊ฐ€ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๋ฐ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ
โš ๏ธ **GitHub.com Fallback** โš ๏ธ