1. 코드리뷰가 끝나고 생각 정리
(23일에 작성한 것에 이어서 프리코스 마치고 4주차 코드리뷰 내용까지 합해 업로드합니다)
(1) Converter에서 validate을 해도 될까? → 해도 된다.
먼저 명칭에 대한 개념적인 정의를 해봅시다!
•
converter : 데이터나 파일의 형식을 변환한다
•
mapper : 데이터 요소 간 매핑을 정의하고 수행한다
•
parser : 데이터 구조를 이해하고 가공한다
이들 각각은 독립적인 기능과 목적을 가지는 건 자명한 사실이지만,
굳이 따지자면 아래와 같은 포함관계를 갖습니다. converter > mapper > parser
결론적으로 converter는 가장 광범위한 역할을 수행합니다. 데이터 형식을 변환하기 위해 때론 매핑이나 파싱 같은 더 복잡한 과정을 내포할 수 있지요.
따라서 클래스 이름을 converter로 지었습니다.
그렇다면 본론으로 돌아와서 converter가 validator의 역할을 포함해도 될까요?
실제 자바 표준 라이브러리 코드 중 일부를 뜯어보자면, converter가 mapper를 가지고, mapper는 parser를 가지고 있습니다.
그리고 각각에서 던지고 있는 예외는 각각 아래와 같습니다.
•
converter : 형식 변환 실패 관련 예외 (ex. HttpMessageNotReadableException)
•
mapper : 데이터 바인딩 관련 예외 (ex. DatabindException)
•
parser : 구문 분석 관련 예외 (ex. JsonParseException)
이 예외들이 결국 현재 제 코드에서 처리 중인 예외 처리 부분과 같은 맥락이라 생각합니다!
•
참고한 자바 코드입니다. 너무 길어서 다 가져오진 못했습니다. 검색해서 직접 들어가보시는 것도 추천드립니다!
// converter가 mapper를 가짐
protected AbstractJackson2HttpMessageConverter(ObjectMapper objectMapper) {
this.defaultObjectMapper = objectMapper;
DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
prettyPrinter.indentObjectsWith(new DefaultIndenter(" ", "\\ndata:"));
this.ssePrettyPrinter = prettyPrinter;
}
}
Plain Text
복사
// mapper가 parser를 이용함
public class ObjectMapper extends ObjectCodec implements Versioned, Serializable {
...
public JsonParser createParser(File src) throws IOException {
this._assertNotNull("src", src);
return this._deserializationConfig.initialize(this._jsonFactory.createParser(src));
}
Plain Text
복사
// parser 예시 1
public abstract class JsonParser implements Closeable, Versioned {
public boolean getBooleanValue() throws IOException {
JsonToken t = this.currentToken();
if (t == JsonToken.VALUE_TRUE) {
return true;
} else if (t == JsonToken.VALUE_FALSE) {
return false;
} else {
throw (new JsonParseException(this, String.format("Current token (%s) not of boolean type", t))).withRequestPayload(this._requestPayload);
}
}
Plain Text
복사
// parser 예시 2
public static int parseInt(String s, int radix) throws NumberFormatException{
if (s == null) {
throw new NumberFormatException("Cannot parse null string");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+') {
throw NumberFormatException.forInputString(s, radix);
}
if (len == 1) { // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s, radix);
}
i++;
}
int multmin = limit / radix;
int result = 0;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
int digit = Character.digit(s.charAt(i++), radix);
if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s, radix);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s, radix);
}
result -= digit;
}
return negative ? result : -result;
} else {
throw NumberFormatException.forInputString(s, radix);
}
}
Plain Text
복사
(2) 연관관계 vs 의존관계 → 더 명확하게 따져보자.
10일차 쯤 의존성에 대해 til에 쓴 적이 있었는데, 당시엔 연관관계와 의존관계 중 모델 간 의존성을 높이는 건 설계에 따라 다르다고 결론 내렸었다. 그렇게 둘의 구분을 모호하게 남겨뒀었는데, 이번 주차 과제를 하면서 둘다 의존성을 갖는 건 명확하지만, 그 의존성의 성격이 다르단걸 직접 겪어 알게 되었다.
•
연관관계
class A {
private B b;
}
Java
복사
◦
의존성이 강하고 영구적임 (강한 의존성)
◦
객체 단위의 기억이 필요함
◦
인스턴스를 변수로 가지기에 여러 메서드에서 사용 가능 (재사용성 좋음)
◦
객체를 한 곳에서 관리하기에 성능과 복잡성 측면에서 좋음
•
의존관계
class A {
public void hihi(B b) {
}
}
Java
복사
◦
메서드 내에서만 발생하기에 의존성이 약하고 일시적임 (느슨한 의존성)
◦
코드가 이해하기 쉬움
◦
로컬 변수와 파라미터로 흐름을 보여주다보니 서술적이고 절차적으로 느껴질 수 있음
각각 장단점이 있겠지만, 느슨한 의존성을 지닌단 점과 이해하기 쉬운 코드라는 점에서 유지보수하기엔 의존관계가 낫단 생각이 들었다.
Today in 프리코스
TIL 작성하기
동반 성장
코드 리뷰 4명 하기
내 코드 리뷰 답변 달기
Search