우아한테크코스/레벨1
로또미션 학습로그
nauni
2021. 2. 24. 15:49
Step1
학습로그 1-1
[TDD] TDD - 5
내용
- TDD 원칙을 따라 구현하고자 하였다. 더 사전에 어떻게 객체에게 책임과 역할을 분배할 것인지 고민하게 되고 전체적인 구조를 생각하게 된다.
//
주석으로 먼저 해야할 일을 적어보고 구현하면 역할 분담을 구체화하는데 도움이 되었다. - 다양한 생성자와 인터페이스를 사용하여 객체의 활용도를 높인다.
- 테스트가 가능하게 최대한 값을 주입받도록 한다.
- 도메인에서 있는 최대한 많은 부분을 테스트코드로 작성하려고 했다.
[Framework] MVC - 3
내용
- TDD를 진행하니 좀 더 도메인 위주로 구현이 가능했다. MVC 패턴을 적용하기 좀 더 수월해진듯 하다.
- View와 Domain의 역할분리를 위해서 다소 반복되더라도 view 위한 코드는 view에서 구현한다.
- InputView라고 받기만 하는 것은 아니고 Input 값을 받기 위한 문구 출력은 InputView에서 해주는 것도 괜찮은 듯 하다.
- 도메인을 대표하는 클래스가 있는 것이 깔끔한 듯 하다.
[OOP] 객체지향 - 4
내용
- 다양한 조건을 테스트하기 위해서 Interface를 작성하여 테스트를 진행하였다. 해당 방법이 전략패턴(구현 알고리즘을 캡슐화)이라고 한다.
- 유의미한 값을 포장하여 그 값에 대한 유효성 체크는 해당 객체가 진행하게 된다.
- 일급컬렉션을 사용하여 리스트를 조작으로부터 보호한다. 리스트를 셋팅하거나 반환할 때는 방어적 복사나 불변객체를 반환한다.
[Java] Functional Interface - 3
내용
- 조건문을 줄이기 위해서 Function Type을 Enum에 적용해보게 되었다. 이것도 일종의 전략패턴인가라는 생각이 든다.
- Enum에서 정적 팩토리 메소드를 사용하여 원하는 타입을 반환할 수 있다.
[Java] BigDecimal - 1
내용
- int 형에서 범위를 넘어가는 버그가 생겨서 찾아보게 되었다.
- 돈과 관련된 정보는 BigDecimal로 하는 것이 좀 더 정확하다고 한다.
- BigDecimal은 String이기 때문에 사칙연산이 되지 않으며, 구현된 메소드를 사용해야 한다.
- 불변 객체이다.
Step2
학습로그 2-1
[Java] BigDecimal - 1
내용
- BigDecimal에서 사칙연산은 BigDecimal을 반환한다. 따라서 새로 더한 값으로 덮어쓰고 싶다면 반환값을 재할당 해주어야 한다.
private BigDecimal getTotalPrize() {
BigDecimal localPrize = BigDecimal.ZERO;
for (Map.Entry<Rank, Integer> result : resultMap.entrySet()) {
localPrize = localPrize.add(
result.getKey().getPrize()
.multiply(BigDecimal.valueOf(result.getValue()))
);
}
return localPrize;
}
이 부분에서 총 합계가 계산이 잘 안되서 원인을 한참동안 찾았다ㅠㅠ
링크
[TDD] DTO, VO - 4
내용
- ✨가능한 모든 도메인에 속하는 코드에 대해 테스트코드를 작성하자!
- Result 클래스는 DTO라고 생각하여 테스트하지 않았는데 생각치 못한 버그가 발생함 (Result도 수익률 계산이라는 로직을 담고 있으므로 순수한 DTO 객체라고 하긴 어려운듯 싶다.)
- DTO와 VO의 차이
- DTO : Entity(Domain)과 View 사이의 통신하며 Presentation Logic이 있는 객체. 로직을 가지고 있지 않는 순수한 데이터 객체. 여기저기 흩어진 값들을 모으는 역할도 하는 듯 싶다. 호출하는 메소드를 줄이기 위해 만든 객체라고도 할 수 있다.
- VO : 값 객체. 원시값을 포장하는 객체 같은 것들을 의미함.
[Java] Builder패턴 - 3
내용
- 생성자 여부만 늘어나는 것이 있다면 Builder 패턴을 사용하면 좋다.
- 꼭 필요한 값은 Builder를 만들때 초기화 해주고, 추가적인 값들은 체이닝을 통해 선택할 수 있다. 계층적으로 설계된 클래스와 함께 사용하기 좋다고 한다.
- 2개 이상의 this() 생성자 체이닝이 이루어질때, 사용하면 유용할 듯 하다.
- Builder를 사용하는데 대한 의견
Builder를 구현해보았으나, 선택적 매개변수를 사용할 때 의미가 있는 것 같다. 결국 Result라는 객체는 WinningNumbers와 LottoTickets가 필수적으로 필요하기 때문에 Builder 패턴을 사용하면 오히려 필요한 정보가 누락되는 상황이 발생할 수 있다. 대신 생성자의 입력값을 더 간단하게 수정할 수 있었다.
[Java] EnumMap -3
내용
- 단순히 HashMap을 EnumMap으로 바꾸는 것 이외에 아무 차이가 없어 보였기에 어떤 효과가 있을지 공부해보았다.
1. Performance
: performance optimization, like a quicker hash computation since all possible keys are known in advance.
2. Functionality
: EnumMap is an ordered map, in that its views will iterate in enum order.
출처:https://www.baeldung.com/java-enum-map
Key 값으로 가지고 있기 위해서는 hashing 작업이 이루어지는데 EnumMap은 이미 알고있는 키이기 때문에 빠른 해싱이 가능하다고 한다. 정확한 내부구현은 어려운 듯 싶으니 해싱이 간편해진다는 요점을 알자.
또다른 기능은 EnumMap은 orderedMap이다. Enum에 명시된 순서를 유지한다.
링크
생성자 관련 피드백
생성자를 통환 활용 - 추상화
- 클라이언트는 최소한의 정보를 아는 것이 좋다.
- 모든 설계는 내가 클라이언트(사용자)라는 관점에서 생각해보면 도움이 된다.
- 해당 서비스를 사용하는 것도 클라이언트고 프레임워크, 라이브러리를 사용하는 것도 클라이언트다. 작게 보면 클래스와 메서드를 사용하는 것도 클라이언트다.
- 추상화 레벨을 높이면 사용은 쉬워지지만 적절한 설계를 하는 것이 좋다. 설계에 따라 확장성을 높이고 싶은 경우 추상화 레벨을 높이는 것은 단점이 될 수 있다.
생성자 관리
- 일반적으로 객체의 생성은 생성자에서 한다.
- 생성자가 많아져 가독성이 떨어지거나 이름을 부여하고 싶다면 정적 팩토리 메서드를 사용한다.
- 매개변수가 많아진다면 빌더 패턴을 사용한다.
- 생성자의 로직이 커져 객체의 가독성을 해친다면 생성만을 담당하는 팩토리를 분리한다.
학습로그 2-2
[OOP] 결합도를 낮추고 응집도를 높이자 - 4
내용
-
Money에서는 LottoTicket을 다 알 필요는 없고 size()만 사용된다. int 값으로 전달해줘도 된다.
-
알 필요가 없는 값은 알지 않도록 하자!
-
금액에 관련된 로직은 Money에서 담당하면 Result는 좀 더 결과를 모아주는 역할만 하는 DTO가 된다.
-
돈과 관련된 정보는 Money가 책임지게 된다. 객체의 목적을 명확히 하자!
[Java] Cache - 4
내용
- LottoNumber의 값은 1~45으로 한정되므로 객체를 캐싱하여 사용하면 불필요한 객체생성을 줄일 수 있다.
학습로그 2-3
[Architecture] MSA - 3
내용
- 로또 미션을 진행하면서 Money 객체를 추상화하여 돈과 관련된 계산 로직은 Money 객체로 관리하면 응집도는 높이고 결합도는 낮출 수 있다.
- 서비스 아키텍처 설계의 핵심이 응집도는 높이고 결합도는 낮추는 것이다.
- 금액 도메인의 역할을 하면서 어느 서비스에서도 활용 가능해진다. 라이브러리 처럼 활용성이 높아지는 것이다
- 서비스 설계를 잘한다면 MSA와 같이 독립적인 서비스로 존재할 수 있다.
- MSA는 MicroService Architecture로 Monolithic과는 대비되는 것이다. 각각의 서비스가 독립적으로 존재하며 곳곳에서 활용이 가능해진다.