-
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๋ฅผ ์ ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ํจํค์ง ๊ตฌ์กฐ ๋ฐ ์ญํ ๋ถ๋ฆฌ๊ฐ ๋ํ๋ฉ๋๋ค:
CreatedThu, 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): ๊ด์ธก๊ฐ์ ๊ฐ์
๊ณต๋ถ์ฐ์ ํน์ง
-
์์(Positive):
CreatedMon, 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)); }CreatedSun, 13 Apr 2025 16:18:45 +0900 -
AES key์ ๋ํ ๋ณด์์ฑ
- ๋ณธ ํฌ์คํธ๋ AES Key๋ ์ด๋ค ์์ผ๋ก ์์ฑํ๊ณ ๋ณด๊ดํ ๊ฒ์ธ์ง์ ๋ํ ChatGPT์ ์๊ฒฌ?์ ๊ธฐ๋ฐ์ผ๋ก ์์ฑ ๋์์ต๋๋ค.
์ง๋ฌธ
- AES/CBC/PKCS5Padding 256 ์ผ๋ก ์๋ณตํํ ๋ secret key๋ฅผ
- ๋ฐ์ด๋๋ฆฌ 32byte๋ฅผ base64 encodeํด์ ์ ์ฅํด๋๊ณ ์๋ณตํธํ์ decodeํด์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
- ์๋จ์ด ์กฐํฉ 32byte ๊ทธ๋๋ก ์ ์ฅํด๋๊ณ ์ฌ์ฉ
- ์๋จ์ด์ _ ์กฐํฉ 32byte ๋ฅผ base64 encodeํด์ ์ ์ฅ
- ์,์ซ์,ํน์๋ฌธ์ ์กฐํฉ์ ๋๋ค์คํธ๋ง 32byte๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉ ์ด๋ค ๋ฐฉ๋ฒ์ด ๋ณด์์ ๊ฐ์ฅ ์์ ํ๊ฐ
๋ต๋ณ
AES/CBC/PKCS5Padding 256 ์ํธํ์์ SecretKey๋ฅผ ์ ์ฅํ๊ณ ์ฌ์ฉํ๋ ๋ฐฉ์์ ๋ณด์์ ๋งค์ฐ ์ค์ํ ์์์ ๋๋ค. ์ฃผ์ด์ง 4๊ฐ์ง ๋ฐฉ์ ์ค ๋ณด์์ ๊ฐ์ฅ ์์ ํ ๋ฐฉ๋ฒ์ ํ๋จํ๋ ค๋ฉด, ๋ค์ ๋ ๊ฐ์ง ๊ธฐ์ค์ ๊ณ ๋ คํด์ผ ํฉ๋๋ค:
CreatedSat, 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์์ ์๊ฐ ๋ก๊ทธ ์ถ๋ ฅ:CreatedFri, 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๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค:CreatedTue, 08 Apr 2025 17:42:13 +0900