의존성 격리 / Fake와 Stub / HTTP 인증 프레임워크 / Enum
- -
오늘 한 일
공부한 내용
ATDD 수업
의존성
변경에 의한 영향을 의미한다. B가 변경될 때 A도 함께 변경된다면, A는 B에 의존한다고 볼 수 있다.
예를 들어 다음과 같은 코드가 있다.
빨간 밑줄친 부분을 보면, line은 getSections를 불러와 Section을 더하는 작업을 하고 있다. LineService는 Sections에 대해 의존하고 있다. 비록 import하지 않았더라도, sections의 add 동작이 변경되면 saveLine 코드가 변경되어야 하기 때문이다.
여기서 이를 다음과 같이 수정한다면 LineService에서 Sections에 대한 의존성을 제거한다고 볼 수 있다.
line.addSection(new Section(line, upStation, downStation, request.getDistance()));
겉으로 보기엔 별 차이가 없는 것 같지만, 있다. 우선, addSection() 메서드로 포장했기 때문에 의존성이 Line으로 격리된다.
캐싱이 안 되는 Stub, Fake 객체로 해결하라
우선 Context Caching과 Stub, Fake라는 개념에 대해 알아야 한다.
Spring 공식문서에 Context Caching이라는 부분을 보면 다음과 같은 설명이 있다.
Once the TestContext framework loads an ApplicationContext (or WebApplicationContext) for a test, that context is cached and reused for all subsequent tests that declare the same unique context configuration within the same test suite. To understand how caching works, it is important to understand what is meant by “unique” and “test suite.”
An ApplicationContext can be uniquely identified by the combination of configuration parameters that is used to load it. Consequently, the unique combination of configuration parameters is used to generate a key under which the context is cached. The TestContext framework uses the following configuration parameters to build the context cache key:
간단하게 설명하자면, 테스트 환경에서 ApplicationContext를 띄울 때, 빈들을 캐싱한다는 의미이다. 이때 빈에 대한 몇 정보들을 활용해서 키를 잡아 사용한다. 그런데 만약 Stubbing을 위해 Mocking한다면, 캐싱을 활용할 수 없어 성능이 떨어진다.

Stub이란 미리 정해진 값을 가지고, 어떠한 행동 요청시 그 값을 반환하도록 하는 것이다. 원본 객체를 활용해야 하기 때문에 Mocking이라는 과정을 필요로 한다.
Fake란 실제로 동작하지만, 실제 코드와는 다른 비슷하게 동작하는 걸 말한다. Fake 객체인 경우, 모킹하지 않고 그냥 그 객체 그대로 갖다 쓰기 때문에 Context에 대해 고민할 필요가 없다.
자세한 내용은 Mock은 Stub이 아니다(Mocks Aren't Stubs)를 읽어보면 더 도움이 된다.
Argument Resolver
Controller에서 파라미터 값을 Custom으로 바인딩할 때 사용된다. ENUM 처리나 JWT 토큰 관련해서 분리할 때 편리하게 사용할 수 있는데, 다음 글에서 잘 다뤄주고 있다.
HTTP 인증 프레임워크, Basic / Bearer 인증
HTTP를 통해 인증할 때는 Authorization이라는 헤더를 필요로 한다. 이때 양식은 다음과 같다.
이때 type에 들어갈 수 있는 값은 Basic, Bearer가 있고, credentials에는 각 타입에 알맞은 고유값들이 들어간다.
Client에서 인증이 필요한 요청을 보냈을 때, Server가 응답하는 상황은 다음과 같다
- Authorization에 값이 들어있지 않으면 Server는 401 Unauthorization을 반환한다.
- 인증 정보는 들어있지만 권한이 없다면 403 Forbidden을 반환한다
- 올바른 인증 정보가 들어있다면 200 OK를 반환한다
이제 type에 대해 알아보자.
- Basic 인증이란, base64로 "사용자ID:비밀번호" 문자열을 인코딩한 것이다. 매우 취약하기 때문에 보안을 위해 HTTPS (TLS) 연결 위에서 발생되어야 한다. 서버에 저장한다는 특징이 있다. 따라서 서버 부담이 클 수 있다.
- Bearer 인증 이란, bearer token이라는 보안 "토큰"을 활용하는 인증 스킴이다. Oauth2.0에서 사용하기 위해 만들어졌다.
Oauth는 제 3자 서비스에게서 데이터를 일부 가져오는 방식이다. 인증 서버는 클라이언트 접근을 관리하며, 리소스 서버는 사용자의 데이터를 관리한다
Bearer 토큰에는 JWT 혹은 16진수 문자열을 사용해야 하며, 사용자 정보가 들어있어선 안된다. 그저 서버에서 클라이언트의 권한을 확인할 수 있는 메타데이터가 토큰에 들어있어야 한다.
이 내용은 Basic 인증과 Bearer 인증의 모든 것에서 쉽고 자세하게 잘 알려준다.
여담으로, 토스 페이먼츠의 경우 결제, 결제 취소, 현금영수증 발급 등 상점에서 자주 사용하는 코어 API의 경우 Basic 인증 방식을 사용한다고 한다.
그리고, 결제 고객을 특정해야 하는 API는 Bearer 인증을 사용한다. 브랜드페이와 같이 결제 고객의 정보를 저장하는 서비스의 경우 그렇다.
pasteHistory
이건 Intellij 기능인데, 수업 중에 너무 좋아보여서 따로 조사했다 ㅋㅋ
shift + 붙여넣기를 누르면 복사한 히스토리가 함께 나오는데, 왔다 갔다 하면서 복사 붙여넣기 해야하는 경우 아아아주 유용하게 사용할 수 있다.
자바 스터디
전략 열거 패턴
이펙티브 자바 "아이템 34 - int 상수 대신 열거 타입을 사용하라"에서 나온 내용인데, 상수들 마다 다른 작업을 하고 싶지만 코드 재사용성이 떨어질 때 사용할 수 있다.
public enum PayrollDay {
MONDAY(WEEKDAY), TUESDAY(WEEKDAY), WEDNESDAY(WEEKDAY), THURSDAY(WEEKDAY), FRIDAY(WEEKDAY), SATURDAY(WEEKEND), SUNDAY(WEEKEND);
private final PayType payType;
PayrollDay(PayType payType) {
this.payType = payType;
}
int pay(int minutesWorked, int payRate) {
return payType.pay(minutesWorked, payRate);
}
enum PayType {
WEEKDAY {
@Override
int overtimePay(int minsWorked, int payRate) {
return minsWorked <= MINS_PER_SHIFT ? 0 : (minsWorked - MINS_PER_SHIFT) * payRate / 2;
}
}, WEEKEND {
@Override
int overtimePay(int minsWorked, int payRate) {
return minsWorked * payRate / 2;
}
};
abstract int overtimePay(int minus, int payRate);
private static final int MINS_PER_SHIFT = 8 * 60;
int pay(int minWorked, int payRate) {
int basePay = minWorked * payRate;
return basePay + overtimePay(minWorked, payRate);
}
}
}
이렇게 분리할 수도 있으나, 모두 다른 일을 한다면 switch문이 효과적이다. enum을 이런 식으로 쪼갤 생각은 못해봤는데 enum을 꼭 상수가 아니더라도 로직 분리를 위해 종종 사용하는 편이라 꽤 유용할 것 같다.
또한, 열거형은 확장에 약하다. 이를 위해 인터페이스를 사용해서 확장하는 효과를 낼 수 있다.
public interface Operation {
double apply(double x, double y);
}
enum basicOperation implements Operation {
PLUS("+") {
@Override
public double apply(double x, double y) { return x + y; }
}, MINUS("-") {
@Override
public double apply(double x, double y) { return x - y; }
}, TIMES("*") {
@Override
public double apply(double x, double y) {
return x * y;
}
}, DIVIDE("/") {
@Override
public double apply(double x, double y) {
return x / y;
}
};
private final String symbol;
basicOperation(String symbol) {
this.symbol = symbol;
}
@Override
public String toString() {
return symbol;
}
}
enum ExtendedOperation implements Operation {
EXP("^") {
@Override
public double apply(double x, double y) {
return Math.pow(x, y);
}
},
REMAINDER("%s") {
@Override
public double apply(double x, double y) {
return x % y;
}
};
private final String symbol;
ExtendedOperation(String symbol) {
this.symbol = symbol;
}
@Override
public String toString() {
return symbol;
}
}
이것도 전략패턴처럼 사용이 가능하다.
비트 필드
여러 값들을 하나의 집합으로 모을 때 비트열을 사용하는 방법이다.
예를 들어, 색을 표현할 때 빨간색을 001, 녹색을 010, 파란색을 100이라고 표현한다고 하자. 그러면 검은색은 빨강 + 초록 + 파랑이므로 111, 노랑은 빨강 + 초록이므로 011로 표현할 수 있다.
이게 흔히 사용되는 예는 파일 권한에서 rwx가 있다. 777, 755할 때 그 rwx이다. 읽기 100(4), 쓰기 010(2), 사용 001(1)을 가진다.
EnumSet을 구현할 때 이 비트 필드를 사용한다고 하는데, 이러한 특징 때문에 Set이지만 순서를 줄 수 있다. 또한 기본 제공 메서드들 속도도 더 빠르다.
비트들을 이런 식으로 활용할 수 있다고 생각은 안 해봤는데, 현실에서도 중복 값 처리할 때 은근 쓸 수 있을 것 같다. 예를 들어 달력이 있다. 달력에서 어떤 날짜들을 카운트할 때, 원하는 날짜들만 골라 한 비트열로 처리하고 이를 수로 표현해 저장하면 훨씬 효율적으로 관리할 수 있겠다는 생각이 든다.
Enum을 공부한 자료는 여기에 정리해 두었다.
일기
꽤 최근에 느낀건데, 어떤 일을 할때 주제를 잡고 그 주제에 대해서 "마스터"하겠다는 생각은 큰 도움이 안 되는 것 같다. 예를 들어 자바 공부를 하건 알고리즘 문제를 풀던, 지금 이번에 모든 걸 파헤치겠다는 마인드로 공부하거나 최적의 코드를 짜겠다는 생각을 하면, 그때부터 골치아파지고 생산력이 떨어진다. 더 나쁜건 삽질한 내용을 곧 잊어버린다.
그러나, 아하~ 이런 게 있구나 정도 폭 넓게 공부하고 나중에 또 보면 또 다른 면을 채워나갈 수 있는 것 같다. 이러한 반복이 오히려 학습이나 일에 더 큰 도움을 주는건 아닐까 생각한다.
인턴에서 전환되지 않았을 때 사수님이 "혹시 완벽주의 경향이 있으신가요?", "왜이렇게 항상 조급해 하세요?" 하는 말들을 해주셨는데 왜 그렇게 보였는지 알 것 같다.
생각해 보니, 하루 공부하는 양과 주제가 적은 편이 아닌데, 나중에 보면 금방 다 잊어버리기 일쑤였던 것 같다. 조급해하지 말고 내 할일을 하자. 언젠가는 많이 쌓여있겠지
'개발일기' 카테고리의 다른 글
정렬하려는 레코드 수가 메모리보다 크다면 / JWT / resolver vs proxy vs handler (0) | 2023.08.01 |
---|---|
peek() / Java 스트림 종류 / 성격 기질 검사 (0) | 2023.07.27 |
테스트하기 쉽도록 객체 쪼개기 / ProxySQL의 캐치프라이즈(문제 해결 전에 문제 인식부터. 문제 인식 전에 도메인부터) / 설계를 뒤엎는 것은 도메인을 조금 더 이해한 것이다 (0) | 2023.07.26 |
Java 스트림과 표준 스트림 (0) | 2023.07.25 |
모바일에선 왜 세션보다 토큰을 선호할까? / 쿠키 / 토큰 (0) | 2023.07.22 |
소중한 공감 감사합니다