각종 후기/우아한테크코스

[우아한 테크코스 3기] LEVEL 2 회고 (109일차)

제이온 (Jayon) 2021. 5. 21.

안녕하세요? 제이온입니다.

 

오늘은 협업 미션 3, 4단계를 구현하기 위해 많은 시간을 페어 프로그래밍에 할애했습니다.

 

 

협업 미션 3단계

 

 

기존의 경로 조회에는 최단 거리 경로와 거리를 알려주었는데, 그 거리만큼의 요금을 구하는 것이 3단계 미션의 목적입니다. 정해진 이동 거리에 따라 금액이 달라지는 것이라 간단했습니다.

 

최단 거리와 관련된 SubwayPath 객체가 있는데, SubwayPath 객체가 요금 객체를 의존하는 것이 부적절하고, 요금 객체 자체도 유틸 성격이 강해서 static class로 정의하였습니다.

 

 

    public static int calculateFare(int distance) {
        if (distance <= BASIC_DISTANCE) {
            return BASIC_FARE;
        }
        return calculateFarePerDistance(distance - BASIC_DISTANCE) + BASIC_FARE;
    }
    private static int calculateFarePerDistance(int distance) {
        if (distance <= MIDDLE_DISTANCE) {
            return calculateOverFare(distance, 5, OVER_FARE);
        }
        return calculateOverFare(distance, 8, OVER_FARE);
    }

 

 

위와 같이 구현하였는데, 중요한 것은 BASIC_DISTANCE나 MIDDLE_DISTANCE와 같이 특정 기준이 되는 거리가 많아질수록 분기가 끝도 없이 많아진다는 사실을 알 수 있습니다. 이 부분은 일단 기능이 돌아가게 구현해 놓고, 추후 전략 패턴 등으로 리팩토링할 예정입니다

 

 

협업 미션 4단계

 

 

4단계는 3단계에서 구한 요금에 여러 가지 추가 정책을 적용해야 합니다. 이전까지는 단순히 거리에 대해 요금을 측정했지만, 이번에는 추가 요금이 있는 노선을 고려해야 하고 로그인된 사용자인지도 고려해야 합니다. 추가 요금이 있는 노선은 테이블에 extra_fare 컬럼을 추가하고, 그것과 관련된 프로덕션 코드를 고치면 됩니다.

 

 

    public static int calculateFareWithLine(int distance, int overLineFare) {
        return calculateFare(distance) + overLineFare;
    }

 

 

3단계때 사용하였던 메소드에다가 추가 노선 요금을 더하는 방식으로 구현했습니다. 단, 여기서 주의해야할 점이 있습니다. 추가 요금 노선을 환승할 때마다 매번 요금을 더하는 것이 아니라는 것이죠. 따라서, 구간 내의 추가 요금 노선을 전부 다 검사하고, 그 중에서 최대 가격만 반환하도록 로직을 짰습니다.

 

 

    public int calculateMaxLineFare() {
        int maxLineFare = 0;
        for (final SectionEdge sectionEdge : sectionEdgeGroup) {
            final Line line = sectionEdge.getLine();
            maxLineFare = Math.max(maxLineFare, line.getFare());
        }
        return maxLineFare;
    }

 

 

Line과 Section 정보가 있는 SectionEdge 객체를 돌면서 최대 추가 요금을 찾았습니다. 그리고 이 요금이 calculateFareWithLine()에서 사용할 overLineFare가 되는 것이죠.

 

 

다음으로, 사용자가 로그인되었는지 확인해야 합니다. 이 부분은 고민이 많았는데, 리졸버 단에서 토큰이 null이면 비로그인자로 판단하기로 결정했습니다.

 

 

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
        String credentials = AuthorizationExtractor.extract(webRequest.getNativeRequest(HttpServletRequest.class));
        if (Objects.isNull(credentials)) {
            return new LoginMember(false);
        }

        LoginMember member = authService.findMemberByToken(credentials);
        if (member.getId() == null) {
            throw new AuthorizationException();
        }
        return member;
    }

 

 

위와 같이 토큰 자체가 null인 경우에 대해 비로그인 사용자로 판단했습니다. 참고로, LoginMember는 isLogin이라는 필드가 있으며, 비로그인자에 대해서는 false로 초기화하게끔 만들었습니다.

 

 

    public static int calculateFareWithLine(LoginMember loginMember, int distance, int overLineFare) {
        int result = calculateFare(distance) + overLineFare;
        if (loginMember.isLogin()) {
            result = discount(loginMember.getAge(), result);
        }
        return result;
    }

    private static int discount(int age, int fare) {
        if (age >= 19) {
            return fare;
        }
        if (age >= 13) {
            return (int) ((fare - 350) * 0.8);
        }
        if (age >= 6) {
            return (int) ((fare - 350) * 0.5);
        }
        return 0;
    }

 

 

그리고 이것을 Fare 객체까지 넘겨받게 해서 할인 정책을 적용했습니다. discount()도 마찬가지로 전략 패턴 등을 통해 리팩토링할 예정입니다.

 

 

정리

오늘은 조앤 덕분에 MySQL 배포, 협업 미션 3단계와 4단계 미션을 끝낼 수 있었다고 생각합니다. 남은 시간은 프론트 크루들이 끝날 때까지 여유롭게 리팩토링이나 개인 공부를 하면 될 것 같습니다.

댓글

추천 글