

역할과 구현을 나누어서 생각을 하면서 개발을 한다.
단순 코드 작성 역량을 키우는 것이 아닌, 전체 그림을 보면서 작성하는 코드부분이 어떤 역할을 하는 지 집중하며 개발을 진행할 예정이다.
자바로만 설계했을 때, 설계도를 보면 MemberServiceImpl 구현체가 MemberRepository를 직접적으로 의존하고 있다.
역할과 구현을 나누고 서로 상호작용하는 것도 분리가 되면 깔끔할 것 같은데, 우선 이 부분은 원래 그런 건지 강의를 더 들어봐야 알 것 같지만, 현재로써는 이부분이 Spring이 해결해줄 것 같다는 생각이 든다.
public enum Grade {
BASIC,
VIP
}
회원 등급과 같이 특정 명칭으로 구분되는 기준은 Enum으로 관리한다.
기준의 종류를 관리하기 편하고, 기준을 비교하는 코드를 작성할 때 기호를 써서 비교를 할 수 있어 코드 가독성을 높일 수 있다.
public class Member {
private Long id;
private String name;
private Grade grade;
public Member(Long id, String name, Grade grade) {
this.id = id;
this.name = name;
this.grade = grade;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Grade getGrade() {
return grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
}
스프링의 도움을 안 받고 개발을 진행하다보니, Lombok를 활용하지 않았다.
추후 Lombok를 활용해야하는 상황과 하지 않아야하는 상황을 구분하는 고민도 해봐야겠다.
public interface MemberRepository {
void save(Member member);
Member findById(Long memberId);
}
역할을 담당하는 회원정보 저장소에 대한 인터페이스다.
public class MemoryMemberRepository implements MemberRepository {
private static Map<Long, Member> store = new HashMap<>();
@Override
public void save(Member member) {
store.put(member.getId(), member);
}
@Override
public Member findById(Long memberId) {
return store.get(memberId);
}
}
회원정보 저장소에 대한 구현체이다.
역할과 구현을 분리함으로써 다형성을 살리고, 확장에 유연하게 대처할 수 있게 개발이 진행되었다.
public interface MemberService {
void join(Member member);
Member findMember(Long memberId);
}
실제로 요청을 받았을 때, 요청을 토대로 저장소에 접근하여 요청을 해결하는 중간 부분이다.
즉, 요청을 해석하고 필요한 로직을 실행하는 부분이다.
public class MemberServiceImpl implements MemberService {
private MemberRepository memberRepository = new MemoryMemberRepository();
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
여기서는 구현 부분에서 MemberRepository의 구현체 MemoryMemberRepository를 의존하고 있다.
이 부분이 스프링에서는 어떻게 해결을 해주는 지, 강의를 들어본서 알아볼 계획이다.
학부생 때는 눈으로 확인할 수 있는 프로젝트, 과제가 전부였기때문에 Test 코드의 중요성을 모르고 있었다.
프로젝트 크기가 커지고, 범위가 넓어질수록 백엔드 코드가 의도에 맞게 돌아가는 지 눈으로 확인하는 것이 비효율적이고, 남들이 볼 때 기준을 모두 다를 수 있기 때문에 Test 코드가 중요하다는 것을 나중에서야 알게되었다.
public class MemberServiceTest {
MemberService memberService = new MemberServiceImpl();
@Test
void join() {
//given
Member member = new Member(1L, "memberA", Grade.VIP);
//when
memberService.join(member);
Member findMember = memberService.findMember(1L);
//then
Assertions.assertEquals(member, findMember);
}
}
테스트 코드 작성요령을 다음과 같다.
1. given - 확인하고 싶은 조건, 상황
2. when - 조건, 상황을 로직에 대입
3. then - 출력된 결과와 예상된 결과를 비교
강의에서는 주문 할인 부분도 있지만, 구현이 다르지 개념적으로 같기 때문에 블로그에는 남기지 않을 것이다.
단순 구현에만 집중했을 때는 놓쳤던 것들을 이제서야 다시 잡고 있는 과정에 있다.
구현에 있어 어떠한 테크닉들을 활용하는 이유들을 알아가는 과정의 재미를 이제서야 느낀다.