본문으둜 κ±΄λ„ˆλ›°κΈ°

🍭 Chapter 8: 경계

πŸŽƒ μ™ΈλΆ€ μ½”λ“œ μ‚¬μš©ν•˜κΈ°β€‹

νŒ¨ν‚€μ§€ μ œκ³΅μžλ‚˜ ν”„λ ˆμž„μ›Œν¬ μ œκ³΅μžλŠ” μ μš©μ„±μ„ μ΅œλŒ€ν•œ λ„“νžˆλ € μ• μ“΄λ‹€. 더 λ§Žμ€ ν™˜κ²½μ—μ„œ λŒμ•„κ°€μ•Ό 더 λ§Žμ€ 고객이 κ΅¬λ§€ν•˜λ‹ˆκΉŒ. 반면, μ‚¬μš©μžλŠ” μžμ‹ μ˜ μš”κ΅¬μ— μ§‘μ€‘ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ°”λž€λ‹€. 이런 κΈ΄μž₯으둜 인해 μ‹œμŠ€ν…œ κ²½κ³„μ—μ„œ λ¬Έμ œκ°€ 생길 μ†Œμ§€κ°€ λ§Žλ‹€.

ν•œ 예둜, java.util.Map을 μ‚΄νŽ΄λ³΄μž. Map은 ꡉμž₯히 λ‹€μ–‘ν•œ μΈν„°νŽ˜μ΄μŠ€λ‘œ μˆ˜λ§Žμ€ κΈ°λŠ₯을 μ œκ³΅ν•œλ‹€. Map이 μ œκ³΅ν•˜λŠ” κΈ°λŠ₯μ„±κ³Ό μœ μ—°μ„±μ€ ν™•μ‹€νžˆ μœ μš©ν•˜μ§€λ§Œ 그만큼 μœ„ν—˜λ„ 크닀.

Map sensors = new HashMap();

Sensor 객체가 ν•„μš”ν•œ μ½”λ“œλŠ” λ‹€μŒκ³Ό 같이 Sensor 객체λ₯Ό κ°€μ Έμ˜¨λ‹€.

Sensor s = (Sensor)sensors.get(sensorId);

μœ„μ™€ 같은 μ½”λ“œκ°€ ν•œ 번이 μ•„λ‹ˆλΌ μ—¬λŸ¬ μ°¨λ‘€ λ‚˜μ˜¨λ‹€. 즉, Map이 λ°˜ν™˜ν•˜λŠ” Objectλ₯Ό μ˜¬λ°”λ₯Έ μœ ν˜•μœΌλ‘œ λ³€ν™˜ν•  μ±…μž„μ€ Map을 μ‚¬μš©ν•˜λŠ” ν΄λΌμ΄μ–ΈνŠΈμ— μžˆλ‹€. κ·Έλž˜λ„ μ½”λ“œλŠ” λ™μž‘ν•œλ‹€. ν•˜μ§€λ§Œ κΉ¨λ—ν•œ μ½”λ“œλΌ λ³΄κΈ°λŠ” μ–΄λ ΅λ‹€. κ²Œλ‹€κ°€ μœ„μ™€ 같은 μ½”λ“œλŠ” μ˜λ„λ„ λΆ„λͺ…νžˆ λ“œλŸ¬λ‚˜μ§€ μ•ŠλŠ”λ‹€. λŒ€μ‹  λ‹€μŒκ³Ό 같이 μ œλ„€λ¦­μŠ€λ₯Ό μ‚¬μš©ν•˜λ©΄ μ½”λ“œ 가독성이 크게 높아진닀.

Map<String, Sensor> sensors = new HashMap<Sensor>();
// ...
Sensor s = sensors.get(sensorId);

κ·Έλ ‡μ§€λ§Œ μœ„ 방법도 Map<String, Sensor>κ°€ μ‚¬μš©μžμ—κ²Œ ν•„μš”ν•˜μ§€ μ•Šμ€ κΈ°λŠ₯κΉŒμ§€ μ œκ³΅ν•œλ‹€λŠ” λ¬Έμ œλŠ” ν•΄κ²°ν•˜μ§€ λͺ»ν•œλ‹€.

λ‹€μŒμ€ Map을 μ’€ 더 κΉ”λ”ν•˜κ²Œ μ‚¬μš©ν•œ μ½”λ“œλ‹€. Sensors μ‚¬μš©μžλŠ” μ œλ„€λ¦­μŠ€κ°€ μ‚¬μš©λ˜μ—ˆλŠ”μ§€ 여뢀에 μ‹ κ²½ μ“Έ ν•„μš”κ°€ μ—†λ‹€. μ•„λž˜μ—μ„œ 보듯, μ œλ„€λ¦­μŠ€μ˜ μ‚¬μš© μ—¬λΆ€λŠ” Sensors μ•ˆμ—μ„œ κ²°μ •ν•œλ‹€.

public class Sensors {
private Map sensors = new HashMap();

public Sensor getById(String id) {
return (Sensor) sensors.get(id);
}

// μ΄ν•˜ μƒλž΅
}

경계 μΈν„°νŽ˜μ΄μŠ€μΈ Map을 Sensors μ•ˆμœΌλ‘œ μˆ¨κΈ΄λ‹€. λ”°λΌμ„œ Map μΈν„°νŽ˜μ΄μŠ€κ°€ λ³€ν•˜λ”λΌλ„ λ‚˜λ¨Έμ§€ ν”„λ‘œκ·Έλž¨μ—λŠ” 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠλŠ”λ‹€. μ œλ„€λ¦­μŠ€λ₯Ό μ‚¬μš©ν•˜λŠ” ν•˜μ§€ μ•Šλ“  더 이상 λ¬Έμ œκ°€ μ•ˆ λœλ‹€. Sensors 클래슀 μ•ˆμ—μ„œ 객체 μœ ν˜•μ„ κ΄€λ¦¬ν•˜κ³  λ³€ν™˜ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

λ˜ν•œ Sensors ν΄λž˜μŠ€λŠ” ν”„λ‘œκ·Έλž¨μ— ν•„μš”ν•œ μΈν„°νŽ˜μ΄μŠ€λ§Œ μ œκ³΅ν•œλ‹€. κ·Έλž˜μ„œ μ½”λ“œλŠ” μ΄ν•΄ν•˜κΈ°λŠ” μ‰½μ§€λ§Œ μ˜€μš©ν•˜κΈ°λŠ” μ–΄λ ΅λ‹€. Sensors ν΄λž˜μŠ€λŠ” (λ‚˜λ¨Έμ§€ ν”„λ‘œκ·Έλž¨μ΄) 섀계 κ·œμΉ™κ³Ό λΉ„μ¦ˆλ‹ˆμŠ€ κ·œμΉ™μ„ λ”°λ₯΄λ„둝 κ°•μ œν•  수 μžˆλ‹€.

Map 클래슀λ₯Ό μ‚¬μš©ν•  λ•Œλ§ˆλ‹€ μœ„μ™€ 같이 μΊ‘μŠν™”ν•˜λΌλŠ” μ†Œλ¦¬κ°€ μ•„λ‹ˆλ‹€. Map을 μ—¬κΈ°μ €κΈ° λ„˜κΈ°μ§€ λ§λΌλŠ” 말이닀. Mapκ³Ό 같은 경계 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ΄μš©ν•  λ•ŒλŠ” 이λ₯Ό μ΄μš©ν•˜λŠ” ν΄λž˜μŠ€λ‚˜ 클래슀 계열 λ°–μœΌλ‘œ λ…ΈμΆœλ˜μ§€ μ•Šλ„λ‘ μ£Όμ˜ν•œλ‹€.

πŸŽƒ 경계 μ‚΄ν”Όκ³  μ΅νžˆκΈ°β€‹

μ™ΈλΆ€ νŒ¨ν‚€μ§€ ν…ŒμŠ€νŠΈκ°€ 우리 μ±…μž„μ€ μ•„λ‹ˆλ‹€. ν•˜μ§€λ§Œ 우리 μžμ‹ μ„ μœ„ν•΄ μš°λ¦¬κ°€ μ‚¬μš©ν•  μ½”λ“œλ₯Ό ν…ŒμŠ€νŠΈν•˜λŠ” 편이 λ°”λžŒμ§ν•˜λ‹€.

μ™ΈλΆ€ μ½”λ“œλ₯Ό μ΅νžˆκΈ°λŠ” μ–΄λ ΅λ‹€. μ™ΈλΆ€ μ½”λ“œλ₯Ό ν†΅ν•©ν•˜κΈ°λ„ μ–΄λ ΅λ‹€. κ³§λ°”λ‘œ 우리μͺ½ μ½”λ“œλ₯Ό μž‘μ„±ν•΄ μ™ΈλΆ€ μ½”λ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” λŒ€μ‹  λ¨Όμ € κ°„λ‹¨ν•œ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό μž‘μ„±ν•΄ μ™ΈλΆ€ μ½”λ“œλ₯Ό 읡히면 μ–΄λ–¨κΉŒ? 점 λ‰΄μ»€ν¬λŠ” 이λ₯Ό ν•™μŠ΅ ν…ŒμŠ€νŠΈλΌ λΆ€λ₯Έλ‹€.

ν•™μŠ΅ ν…ŒμŠ€νŠΈλŠ” ν”„λ‘œκ·Έλž¨μ—μ„œ μ‚¬μš©ν•˜λ €λŠ” λ°©μ‹λŒ€λ‘œ μ™ΈλΆ€ APIλ₯Ό ν˜ΈμΆœν•œλ‹€. ν†΅μ œλœ ν™˜κ²½μ—μ„œ APIλ₯Ό μ œλŒ€λ‘œ μ΄ν•΄ν•˜λŠ”μ§€λ₯Ό ν™•μΈν•˜λŠ” μ…ˆμ΄λ‹€. ν•™μŠ΅ ν…ŒμŠ€νŠΈλŠ” APIλ₯Ό μ‚¬μš©ν•˜λ €λŠ” λͺ©μ μ— μ΄ˆμ μ„ λ§žμΆ˜λ‹€.

πŸŽƒ log4jμ΅νžˆκΈ°β€‹

λ‘œκΉ… κΈ°λŠ₯을 직접 κ΅¬ν˜„ν•˜λŠ” λŒ€μ‹  μ•„νŒŒμΉ˜μ˜ log4j νŒ¨ν‚€μ§€λ₯Ό μ‚¬μš©ν•˜λ € ν•œλ‹€κ³  κ°€μ •ν•˜μž. λ¬Έμ„œλ₯Ό μžμ„Ένžˆ 읽기 전에 첫 번째 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό μž‘μ„±ν•œλ‹€. 화면에 helloλ₯Ό 좜λ ₯ν•˜λŠ” ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ‹€.

@Test
public void testLogCreate() {
Logger logger = Logger.getLogger("MyLogger");
logger.info("hello");
}

ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό λŒλ Έλ”λ‹ˆ AppenderλΌλŠ” λ­”κ°€κ°€ ν•„μš”ν•˜λ‹€λŠ” 였λ₯˜κ°€ λ°œμƒν•œλ‹€. λ¬Έμ„œλ₯Ό μ’€ 더 μ½μ–΄λ³΄λ‹ˆ ConsoleAppenderλΌλŠ” ν΄λž˜μŠ€κ°€ μžˆλ‹€. κ·Έλž˜μ„œ ConsoleAppenderλ₯Ό μƒμ„±ν•œ ν›„ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό λ‹€μ‹œ λŒλ¦°λ‹€.

@Test
public void testLogAddAppender() {
Logger logger = Logger.getLogger("MyLogger");
ConsoleAppender appender = new ConsoleAppender();
logger.addAppender(appender);
logger.info("hello");
}

μ΄λ²ˆμ—λŠ” Appender에 좜λ ₯ 슀트림이 μ—†λ‹€λŠ” 사싀을 λ°œκ²¬ν•œλ‹€. μ΄μƒν•˜λ‹€. 좜λ ₯ 슀트림이 μžˆμ–΄μ•Ό 정상이 μ•„λ‹Œκ°€? κ΅¬κΈ€μ—μ„œ κ²€μƒ‰ν•œ ν›„ λ‹€μŒκ³Ό 같이 μ‹œλ„ν•œλ‹€.

@Test
public void testLogAddAppender() {
Logger logger = Logger.getLogger("MyLogger");
logger.removeAllAppenders();
logger.addAppender(new ConsoleAppender(
new PatternLayout("%p %t %m%n"),
ConsoleAppender.SYSTEM_OUT
));
logger.info("hello");
}

μ΄μ œμ„œμ•Ό μ œλŒ€λ‘œ λŒμ•„κ°„λ‹€. μ§€κΈˆκΉŒμ§€ κ°„λ‹¨ν•œ μ½˜μ†” 둜거 μ΄ˆκΈ°ν™”ν•˜λŠ” 방법을 μ΅ν˜”μœΌλ‹ˆ, 이제 λͺ¨λ“  지식을 λ…μžμ μΈ 둜거 클래슀둜 μΊ‘μŠν™”ν•œλ‹€. 그러면 λ‚˜λ¨Έμ§€ ν”„λ‘œκ·Έλž¨μ€ log4j 경계 μΈν„°νŽ˜μ΄μŠ€λ₯Ό λͺ°λΌλ„ λœλ‹€.

πŸŽƒ ν•™μŠ΅ ν…ŒμŠ€νŠΈλŠ” 곡짜 이상이닀.​

ν•™μŠ΅ ν…ŒμŠ€νŠΈλŠ” 곡짜 이상이닀. νˆ¬μžν•˜λŠ” λ…Έλ ₯보닀 μ–»λŠ” μ„±κ³Όκ°€ 더 크닀. νŒ¨ν‚€μ§€ μƒˆ 버전이 λ‚˜μ˜¨λ‹€λ©΄ ν•™μŠ΅ ν…ŒμŠ€νŠΈλ₯Ό 돌렀 차이가 μžˆλŠ”μ§€ ν™•μΈν•œλ‹€. ν•™μŠ΅ ν…ŒμŠ€νŠΈλŠ” νŒ¨ν‚€μ§€κ°€ μ˜ˆμƒλŒ€λ‘œ λ„λŠ”μ§€ κ²€μ¦ν•œλ‹€. 일단 ν†΅ν•©ν•œ 이후라고 ν•˜λ”λΌλ„ νŒ¨ν‚€μ§€κ°€ 우리 μ½”λ“œμ™€ ν˜Έν™˜λ˜λ¦¬λΌλŠ” 보μž₯은 μ—†λ‹€. νŒ¨ν‚€μ§€ μž‘μ„±μžμ—κ²Œ μ½”λ“œλ₯Ό λ³€κ²½ν•  ν•„μš”κ°€ 생길지도 λͺ¨λ₯Έλ‹€. νŒ¨ν‚€μ§€ μž‘μ„±μžλŠ” 버그λ₯Ό μˆ˜μ •ν•˜κ³  κΈ°λŠ₯도 μΆ”κ°€ν•œλ‹€. νŒ¨ν‚€μ§€ μƒˆ 버전이 λ‚˜μ˜¬ λ•Œλ§ˆλ‹€ μƒˆλ‘œμš΄ μœ„ν—˜μ΄ 생긴닀. μƒˆ 버전이 우리 μ½”λ“œμ™€ ν˜Έν™˜λ˜μ§€ μ•ŠμœΌλ©΄ ν•™μŠ΅ ν…ŒμŠ€νŠΈκ°€ 이 사싀을 κ³§λ°”λ‘œ λ°ν˜€λ‚Έλ‹€.

ν•™μŠ΅ ν…ŒμŠ€νŠΈλ₯Ό μ΄μš©ν•œ ν•™μŠ΅μ΄ ν•„μš”ν•˜λ“  그렇지 μ•Šλ“ , μ‹€μ œ μ½”λ“œμ™€ λ™μΌν•œ λ°©μ‹μœΌλ‘œ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λŠ” ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€κ°€ ν•„μš”ν•˜λ‹€. 이런 경계 ν…ŒμŠ€νŠΈκ°€ μžˆλ‹€λ©΄ νŒ¨ν‚€μ§€μ˜ μƒˆ λ²„μ „μœΌλ‘œ μ΄μ „ν•˜κΈ° μ‰¬μ›Œμ§„λ‹€. 그렇지 μ•Šλ‹€λ©΄ 낑은 버전을 ν•„μš” μ΄μƒμœΌλ‘œ μ˜€λž«λ™μ•ˆ μ‚¬μš©ν•˜λ €λŠ” μœ ν˜Ήμ— 빠지기 쉽닀.

πŸŽƒ 아직 μ‘΄μž¬ν•˜μ§€ μ•Šμ€ μ½”λ“œλ₯Ό μ‚¬μš©ν•˜κΈ°β€‹

경계와 κ΄€λ ¨ν•΄ 또 λ‹€λ₯Έ μœ ν˜•μ€ μ•„λŠ” μ½”λ“œμ™€ λͺ¨λ₯΄λŠ” μ½”λ“œλ₯Ό λΆ„λ¦¬ν•˜λŠ” 경계닀. λ•Œλ‘œλŠ” 우리 지식이 경계λ₯Ό λ„˜μ–΄ λ―ΈμΉ˜μ§€ λͺ»ν•˜λŠ” μ½”λ“œ μ˜μ—­λ„ μžˆλ‹€. λ•Œλ‘œλŠ” μ•Œλ €κ³  해도 μ•Œ μˆ˜κ°€ μ—†λ‹€. λ•Œλ‘œλŠ” 더 이상 내닀보지 μ•ŠκΈ°λ‘œ κ²°μ •ν•œλ‹€.

μš°λ¦¬κ°€ λ°”λΌλŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λ©΄ μš°λ¦¬κ°€ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ „μ μœΌλ‘œ ν†΅μ œν•œλ‹€λŠ” μž₯점이 생긴닀. λ˜ν•œ μ½”λ“œ 가독성도 높아지고 μ½”λ“œ μ˜λ„λ„ λΆ„λͺ…해진닀. 이와 같은 μ„€κ³„λŠ” ν…ŒμŠ€νŠΈλ„ μ•„μ£Ό νŽΈν•˜λ‹€. μ μ ˆν•œ Fake 클래슀λ₯Ό μ‚¬μš©ν•˜λ©΄ ν•΄λ‹Ή 클래슀λ₯Ό ν…ŒμŠ€νŠΈν•  수 μžˆλ‹€. API μΈν„°νŽ˜μ΄μŠ€κ°€ λ‚˜μ˜¨ λ‹€μŒ 경계 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό 생성해 μš°λ¦¬κ°€ APIλ₯Ό μ˜¬λ°”λ₯΄κ²Œ μ‚¬μš©ν•˜λŠ”μ§€ ν…ŒμŠ€νŠΈν•  μˆ˜λ„ μžˆλ‹€.

πŸŽƒ κΉ¨λ—ν•œ 경계​

κ²½κ³„μ—μ„œλŠ” ν₯미둜운 일이 많이 λ²Œμ–΄μ§„λ‹€. 변경이 λŒ€ν‘œμ μΈ μ˜ˆλ‹€. μ†Œν”„νŠΈμ›¨μ–΄ 섀계가 μš°μˆ˜ν•˜λ‹€λ©΄ λ³€κ²½ν•˜λŠ”λ° λ§Žμ€ νˆ¬μžμ™€ μž¬μž‘μ—…μ΄ ν•„μš”ν•˜μ§€ μ•Šλ‹€. μ—„μ²­λ‚œ μ‹œκ°„κ³Ό λ…Έλ ₯κ³Ό μž¬μž‘μ—…μ„ μš”κ΅¬ν•˜μ§€ μ•ŠλŠ”λ‹€. ν†΅μ œν•˜μ§€ λͺ»ν•˜λŠ” μ½”λ“œλ₯Ό μ‚¬μš©ν•  λ•ŒλŠ” λ„ˆλ¬΄ λ§Žμ€ 투자λ₯Ό ν•˜κ±°λ‚˜ ν–₯ν›„ λ³€κ²½ λΉ„μš©μ΄ μžλ‚˜μΉ˜κ²Œ 컀지지 μ•Šλ„λ‘ κ°λ³„νžˆ μ£Όμ˜ν•΄μ•Ό ν•œλ‹€.

경계에 μœ„μΉ˜ν•˜λŠ” μ½”λ“œλŠ” κΉ”λ”νžˆ λΆ„λ¦¬ν•œλ‹€. λ˜ν•œ κΈ°λŒ€μΉ˜λ₯Ό μ •μ˜ν•˜λŠ” ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ„ μž‘μ„±ν•œλ‹€. 이μͺ½ μ½”λ“œμ—μ„œ μ™ΈλΆ€ νŒ¨ν‚€μ§€λ₯Ό μ„Έμ„Έν•˜κ²Œ μ•Œμ•„μ•Ό ν•  ν•„μš”κ°€ μ—†λ‹€. ν†΅μ œκ°€ λΆˆκ°€λŠ₯ν•œ μ™ΈλΆ€ νŒ¨ν‚€μ§€μ— μ˜μ‘΄ν•˜λŠ” λŒ€μ‹  ν†΅μ œκ°€ κ°€λŠ₯ν•œ 우리 μ½”λ“œμ— μ˜μ‘΄ν•˜λŠ” 편이 훨씬 더 μ’‹λ‹€. μžμΉ«ν•˜λ©΄ 였히렀 μ™ΈλΆ€ μ½”λ“œμ— νœ˜λ‘˜λ¦¬κ³  λ§Œλ‹€.

μ™ΈλΆ€ νŒ¨ν‚€μ§€λ₯Ό ν˜ΈμΆœν•˜λŠ” μ½”λ“œλ₯Ό κ°€λŠ₯ν•œ 쀄여 경계λ₯Ό κ΄€λ¦¬ν•˜μž. Mapμ—μ„œ 봀듯이, μƒˆλ‘œμš΄ 클래슀둜 경계λ₯Ό κ°μ‹Έκ±°λ‚˜ μ•„λ‹ˆλ©΄ ADAPTER νŒ¨ν„΄μ„ μ‚¬μš©ν•΄ μš°λ¦¬κ°€ μ›ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό νŒ¨ν‚€μ§€κ°€ μ œκ³΅ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€λ‘œ λ³€ν™˜ν•˜μž. μ–΄λŠ 방법이든 μ½”λ“œ 가독성이 높아지며, 경계 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λŠ” 일관성도 높아지며, μ™ΈλΆ€ νŒ¨ν‚€μ§€κ°€ λ³€ν–ˆμ„ λ•Œ λ³€κ²½ν•  μ½”λ“œλ„ 쀄어든닀.