Avatar
๐Ÿ˜‰

Organizations

  • DDD(Domain-Driven Design, ๋„๋ฉ”์ธ ์ฃผ๋„ ์„ค๊ณ„)๋Š” ๋ณต์žกํ•œ ์†Œํ”„ํŠธ์›จ์–ด ์‹œ์Šคํ…œ์„ ์„ค๊ณ„ํ•  ๋•Œ ๋น„์ฆˆ๋‹ˆ์Šค ๋„๋ฉ”์ธ(์—…๋ฌด ์˜์—ญ) ์„ ์ค‘์‹ฌ์— ๋‘๊ณ  ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐฉ๋ฒ•๋ก ์ด์—์š”. ์—๋ฆญ ์—๋ฐ˜์Šค(Eric Evans)์˜ ์ฑ… *“Domain-Driven Design: Tackling Complexity in the Heart of Software”*์—์„œ ์ฒ˜์Œ ์ œ์•ˆ๋˜์—ˆ๊ณ , ํŠนํžˆ ๋„๋ฉ”์ธ ๋ณต์žก์„ฑ์ด ๋†’์€ ์‹œ์Šคํ…œ์—์„œ ๊ฐ•๋ ฅํ•œ ํšจ๊ณผ๋ฅผ ๋ฐœํœ˜ํ•ฉ๋‹ˆ๋‹ค.


    โœ… DDD๋ž€?

    ๊ฐ„๋‹จํžˆ ๋งํ•ด DDD๋Š”:

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

    โœ… DDD์˜ ํ•ต์‹ฌ ๊ฐœ๋…

    ๊ฐœ๋… ์„ค๋ช…
    Entity ์‹๋ณ„์ž๊ฐ€ ์žˆ์–ด ๊ณ ์œ ํ•˜๊ฒŒ ๊ตฌ๋ถ„๋˜๋Š” ๊ฐ์ฒด (ex. Order, User)
    Value Object ์‹๋ณ„์ž ์—†์ด ๊ฐ’ ์ž์ฒด๋กœ ์˜๋ฏธ๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด (ex. Address, Money)
    Aggregate ๋„๋ฉ”์ธ ๊ฐ์ฒด๋“ค์˜ ๊ตฐ์ง‘. ํ•˜๋‚˜์˜ ๋ฃจํŠธ ์—”ํ‹ฐํ‹ฐ(Aggregate Root)๊ฐ€ ์กด์žฌ
    Repository ๋„๋ฉ”์ธ ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•˜๊ณ  ์กฐํšŒํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค (findById, save)
    Service (๋„๋ฉ”์ธ ์„œ๋น„์Šค) ํŠน์ • ์—”ํ‹ฐํ‹ฐ์— ์†ํ•˜์ง€ ์•Š๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋‹ด๋‹น
    Factory ๋ณต์žกํ•œ ๊ฐ์ฒด ์ƒ์„ฑ ๋กœ์ง ๋‹ด๋‹น
    Bounded Context ํŠน์ • ๋„๋ฉ”์ธ ๋ชจ๋ธ์ด ์ ์šฉ๋˜๋Š” ๋ช…ํ™•ํ•œ ๊ฒฝ๊ณ„

    โœ… Spring Boot์—์„œ DDD ์ฝ”๋“œ์ƒ ํŠน์ง•

    Spring Boot์—์„œ DDD๋ฅผ ์ ์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŒจํ‚ค์ง€ ๊ตฌ์กฐ ๋ฐ ์—ญํ•  ๋ถ„๋ฆฌ๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค:

    Created Thu, 17 Apr 2025 18:54:11 +0900
  • **๊ณต๋ถ„์‚ฐ(Covariance)**์€ ๋‘ ๋ณ€์ˆ˜ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ์ธก์ •ํ•˜๋Š” ํ†ต๊ณ„์  ๊ฐœ๋…์œผ๋กœ, ํ•œ ๋ณ€์ˆ˜์˜ ๋ณ€ํ™”๊ฐ€ ๋‹ค๋ฅธ ๋ณ€์ˆ˜์˜ ๋ณ€ํ™”์™€ ์–ด๋–ป๊ฒŒ ์—ฐ๊ด€๋˜์–ด ์žˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๊ณต๋ถ„์‚ฐ์€ ๋ณ€์ˆ˜ ๊ฐ„์˜ ๋ฐฉํ–ฅ์„ฑ๊ณผ ํฌ๊ธฐ๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

    ๊ณต๋ถ„์‚ฐ์˜ ์ •์˜

    ๊ณต๋ถ„์‚ฐ์€ ๋‘ ๋ณ€์ˆ˜ (X)์™€ (Y)์˜ ๊ฐ’๋“ค์ด ๊ฐ๊ฐ ํ‰๊ท ์—์„œ ๋ฒ—์–ด๋‚œ ์ •๋„๋ฅผ ๊ณฑํ•œ ๊ฐ’์˜ ํ‰๊ท ์œผ๋กœ ๊ณ„์‚ฐ๋ฉ๋‹ˆ๋‹ค.
    ์ˆ˜์‹์œผ๋กœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

    [ \text{Cov}(X, Y) = \frac{\sum_{i=1}^n (X_i - \bar{X})(Y_i - \bar{Y})}{n} ]

    • (X_i, Y_i): ๊ฐ ๋ณ€์ˆ˜ (X)์™€ (Y)์˜ ๊ด€์ธก๊ฐ’
    • (\bar{X}, \bar{Y}): ๋ณ€์ˆ˜ (X)์™€ (Y)์˜ ํ‰๊ท ๊ฐ’
    • (n): ๊ด€์ธก๊ฐ’์˜ ๊ฐœ์ˆ˜

    ๊ณต๋ถ„์‚ฐ์˜ ํŠน์ง•

    1. ์–‘์ˆ˜(Positive):

    Created Mon, 14 Apr 2025 09:10:45 +0900
  • java์—์„œ AES ์•”๋ณตํ˜ธํ™” ์ฝ”๋“œ ์˜ˆ์ œ

    ์•”ํ˜ธํ™”

        public static String encryptAes(String plainText) throws Exception {
            Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] key = Base64.decodeBase64("YOUR_KEY");
            byte[] iv = Base64.decodeBase64("YOUR_INITIAL_VALUE");
    
            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
            c.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv));
            byte[] encryptedByte = c.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
    
            return new String(Base64.encodeBase64(encryptedByte));
        }
    

    ๋ณตํ˜ธํ™”

        public static String decryptAes(String cipherText) throws Exception {
            Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] key = Base64.decodeBase64("YOUR_KEY");
            byte[] iv = Base64.decodeBase64("YOUR_INITIAL_VALUE");
    
            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
            c.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv));
            byte[] encryptedByte = c.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
    
            return new String(Base64.encodeBase64(encryptedByte));
        }
    
    Created Sun, 13 Apr 2025 16:18:45 +0900
  • AES key์— ๋Œ€ํ•œ ๋ณด์•ˆ์„ฑ

    • ๋ณธ ํฌ์ŠคํŠธ๋Š” AES Key๋Š” ์–ด๋–ค ์‹์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ๋ณด๊ด€ํ•  ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ChatGPT์˜ ์˜๊ฒฌ?์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘์„ฑ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

    ์งˆ๋ฌธ

    • AES/CBC/PKCS5Padding 256 ์œผ๋กœ ์•”๋ณตํ™”ํ• ๋•Œ secret key๋ฅผ
    1. ๋ฐ”์ด๋„ˆ๋ฆฌ 32byte๋ฅผ base64 encodeํ•ด์„œ ์ €์žฅํ•ด๋†“๊ณ  ์•”๋ณตํ˜ธํ™”์‹œ decodeํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
    2. ์˜๋‹จ์–ด ์กฐํ•ฉ 32byte ๊ทธ๋Œ€๋กœ ์ €์žฅํ•ด๋†“๊ณ  ์‚ฌ์šฉ
    3. ์˜๋‹จ์–ด์™€ _ ์กฐํ•ฉ 32byte ๋ฅผ base64 encodeํ•ด์„œ ์ €์žฅ
    4. ์˜,์ˆซ์ž,ํŠน์ˆ˜๋ฌธ์ž ์กฐํ•ฉ์˜ ๋žœ๋ค์ŠคํŠธ๋ง 32byte๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ ์–ด๋–ค ๋ฐฉ๋ฒ•์ด ๋ณด์•ˆ์ƒ ๊ฐ€์žฅ ์•ˆ์ „ํ•œ๊ฐ€

    ๋‹ต๋ณ€

    AES/CBC/PKCS5Padding 256 ์•”ํ˜ธํ™”์—์„œ SecretKey๋ฅผ ์ €์žฅํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์€ ๋ณด์•ˆ์— ๋งค์šฐ ์ค‘์š”ํ•œ ์š”์†Œ์ž…๋‹ˆ๋‹ค. ์ฃผ์–ด์ง„ 4๊ฐ€์ง€ ๋ฐฉ์‹ ์ค‘ ๋ณด์•ˆ์ƒ ๊ฐ€์žฅ ์•ˆ์ „ํ•œ ๋ฐฉ๋ฒ•์„ ํŒ๋‹จํ•˜๋ ค๋ฉด, ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ๊ธฐ์ค€์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

    Created Sat, 12 Apr 2025 16:18:45 +0900
  • ์„œ๋ฒ„ ์‘๋‹ต ์ง€์—ฐ์ด๋‚˜ Timeout ๊ด€๋ จ ์ด์Šˆ๋ฅผ ์ถ”์ ํ•˜๋ ค๋ฉด, ์š”์ฒญ/์‘๋‹ต ์‹œ๊ฐ„ ๋กœ๊ทธ๋ฅผ ์ง์ ‘ ๋‚จ๊ธฐ๊ฑฐ๋‚˜, Spring์— ์ปค์Šคํ…€ Filter ๋˜๋Š” Feign Logger ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์•„์ฃผ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ๋‘ ๊ฐ€์ง€ ์ผ€์ด์Šค ๋ชจ๋‘ ๋‹ค๋ค„๋ณผ๊ฒŒ์š”.


    โœ… 1. Feign ์š”์ฒญ/์‘๋‹ต ์‹œ๊ฐ„ ๋กœ๊น… ํ•„ํ„ฐ

    ๐Ÿ”ง ์š”์ฒญ ์ „์— ์‹œ๊ฐ„ ์ €์žฅ โ†’ ์‘๋‹ต ํ›„ ์†Œ์š” ์‹œ๊ฐ„ ์ธก์ •

    @Component
    public class FeignRequestTimingInterceptor implements RequestInterceptor {
    
        private static final Logger log = LoggerFactory.getLogger(FeignRequestTimingInterceptor.class);
    
        @Override
        public void apply(RequestTemplate template) {
            template.header("X-Request-Start-Time", String.valueOf(System.currentTimeMillis()));
        }
    }
    

    ๊ทธ๋ฆฌ๊ณ  ErrorDecoder๋‚˜ FeignClientExceptionDecoder ์—์„œ ์‹œ๊ฐ„ ๋กœ๊ทธ ์ถœ๋ ฅ:

    Created Fri, 11 Apr 2025 18:54:11 +0900
  • @JsonIgnore๋ฅผ ๋ถ™์ด๋ฉด ํ•ด๋‹น ํ•„๋“œ๋Š” JSON ๋ณ€ํ™˜ ์‹œ ๋ฌด์กฐ๊ฑด ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๊ฐ’์ด ์žˆ๋“  ์—†๋“  ๊ด€๊ณ„์—†์ด JSON ๊ฒฐ๊ณผ์— ํ•„๋“œ ์ž์ฒด๊ฐ€ ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

    ์˜ˆ์‹œ๋กœ ๋ณด๋ฉด:

    public class User {
        private String name;
    
        @JsonIgnore
        private String password;
    
        // getters/setters
    }
    

    ์œ„ ๊ฐ์ฒด๋ฅผ JSON์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋ฉด (์˜ˆ: name="Alice", password="secret"์ด๋”๋ผ๋„):

    {
      "name": "Alice"
    }
    

    password ํ•„๋“œ๋Š” ๋ฌด์กฐ๊ฑด ๋น ์ง‘๋‹ˆ๋‹ค.


    ๋ฐ˜๋ฉด, ๊ฐ’์ด ์—†์„ ๋•Œ๋งŒ ํ•„๋“œ๋ฅผ ์ œ์™ธํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด @JsonInclude๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

    Created Tue, 08 Apr 2025 17:42:13 +0900