본문 바로가기

프로그래밍/spring

[스프링 입문] 회원 관리 예제 - 백엔드 개발

시작에 앞서 이 글은 인프런 김영한 님의 강의를 정리하며 쓴 글입니다.

웹 백엔드를 공부하시는 분이라면 꼭 김영한님의 강의를 들어보시길 추천합니다.

 

컨트롤러: 웹 MVC의 컨트롤러 역할

서비스: 핵심 비즈니스 로직 구현

리포지토리: 데이터베이스에 접근, 도메인 객체를 DB에 저장하고 관리

도메인: 비즈니스 도메인 객체, 예) 회원, 주문, 쿠폰 등등 주로 데이터베이스에 저장하고 관리됨

 

 

레포지토리 구현

먼저, 데이터 저장소가 어떤 것을 사용할지 아직 정해지지 않았으므로, 우선은 레포지토리 인터페이스를 설계합니다.

 

public interface MemberRepository {
    Optional<Member> findById(Long id);
    Optional<Member> findByName(String name);
    List<Member> findAll();
    void save(Member member);
}

 

 

그 후에는 이 인터페이스를 구현하는 구체적인 클래스를 작성합니다.

 

public class MemoryMemberRepository implements MemberRepository {
    private static Map<Long, Member> store = new HashMap<>();
    private static long sequence = 0L;

    @Override
    public Optional<Member> findById(Long id) {
        return Optional.ofNullable(store.get(id));
    }

    @Override
    public Optional<Member> findByName(String name) {
        return store.values().stream()
                .filter(member -> member.getName().equals(name))
                .findFirst();
    }

    @Override
    public List<Member> findAll() {
        return new ArrayList<>(store.values());
    }

    @Override
    public void save(Member member) {
        member.setId(++sequence);
        store.put(member.getId(), member);
    }
}

 

여기서 Optional은 null을 처리하는데 유용한 자바 클래스입니다.

그리고 이 레포지토리 클래스에 대한 테스트 코드를 작성합니다.

 

public class MemoryMemberRepositoryTest {
    private MemberRepository repository = new MemoryMemberRepository();

    @Test
    public void save() {
        Member member = new Member("test");
        repository.save(member);
        Member result = repository.findById(member.getId()).orElse(null);
        assertThat(result).isEqualTo(member);
    }

    // 다른 테스트 코드들도 비슷한 방식으로 작성합니다.
}

 

서비스 구현

 

다음은 서비스 모듈을 구현합니다. 서비스는 핵심 비즈니스 로직을 구현하는 부분입니다.

 

public class MemberService {
    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    public Long join(Member member) {
        validateDuplicateMember(member); // 중복 회원 검증
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) {
        memberRepository.findByName(member.getName())
                .ifPresent(m -> {
                    throw new IllegalStateException("이미 존재하는 회원입니다.");
                });
    }
}

 

 

테스트 코드 작성 시 주의사항

  • given, when, then 패턴을 사용하여 테스트 코드를 작성하면 가독성이 좋아집니다.
  • 중복된 회원이 있는 경우 테스트할 때, 예외가 발생해야 하는 상황에 대한 테스트도 꼼꼼하게 작성하세요.
  • 테스트 코드는 서로 의존관계가 없어야 합니다. 테스트 코드 실행 순서에 따라 의존성이 생기면 안 되니까요.


    테스트 실행
  1. 프로젝트 루트 디렉토리에서 터미널에 ./gradlew test를 입력하여 테스트를 실행합니다.
  2. 테스트가 성공하면 각 모듈들이 제대로 동작하고 있다는 것을 확인할 수 있습니다.
  3. 마지막으로, 작성한 테스트 코드를 실행하여 각 모듈들이 제대로 동작하는지 확인합니다.

이렇게 모듈별로 설계하고 테스트하는 것은 코드의 견고성과 유지보수성을 높이는 데에 도움이 됩니다. 테스트 코드를 통해 각 모듈이 예상대로 동작하는지 확인하고, 나중에 추가된 기능이나 수정된 기능이 기존 코드에 영향을 주지 않도록 할 수 있습니다.