백엔드 개발 - 회원 관리

ny0011·2022년 10월 7일

스프링 입문

목록 보기
4/4

간단한 회원 관리 시스템 만들기~

비즈니스 요구사항 정리

  • 데이터 : 회원ID, 이름
  • 기능 : 회원 등록, 조회
  • 아직 데이터 저장소가 선정되지 않음(어떤 DB 쓸 지 모름)

일반적인 웹 애플리케이션 계층 구조

  • 컨트롤러: 웹 MVC의 컨트롤러 역할, API 만들기 등
  • 서비스: 도메인 객체를 사용해 핵심 비즈니스 로직을 구현하는 곳
    • ex) 회원 중복가입 막기
  • 리포지토리: 데이터베이스에 접근, 도메인 객체를 DB에 저장하고 관리
  • 도메인 : 주로 데이터베이스에 저장하고 관리되는 비즈니스 도메인 객체
    • 예) 회원, 주문, 쿠폰
  • DB

클래스 의존 관계

  • 아직 데이터 저장소가 선정되지 않아서, 우선 인터페이스로 구현 클래스를 변경할 수 있도록 설계
  • 데이터 저장소는 RDB, NoSQL 등등 다양한 저장소를 고민중인 상황으로 가정
  • 개발을 진행하기 위해서 초기 개발 단계에서는 구현체로 가벼운 메모리 기반의 데이터 저장소 사용
  • 요런 설계가 중요한 듯.. 멤버 리포지토리를 인터페이스로 만들고 메모리에 데이터를 저장하게 함

회원 도메인과 리포지토리 만들기

domain

  • 회원 객체

repository

  • 회원 리포지토리 인터페이스
    • Optional 객체 : 자바 8에 추가됨. 값이 null로 반환될 때 처리해주는 기능
    • 회원 객체의 private 변수
      • Long id
      • String name
  • 회원 리포지토리 메모리 구현체
    • public Member save(Member member) : 회원을 repository에 저장하는 함수(Create)
      • 공유되는 변수의 경우 한 쪽에서 쓸 때 lock을 걸지 않으면 동시성 문제가 생긴다(multi-thread 환경)
      • HashMap보다 ConcurrentHashMap을 사용해야 함
      • private 변수 : store, sequence
        • Map<Long, Member> store : <id, 회원 객체 하나>를 같이 저장함
        • Long sequence : id값을 결정. 회원이 늘어날 때마다 1씩 증가됨
    • public Optional<Member> findById(Long id) : id 값으로 회원 검색(Read)
      • 회원이 없을 경우가 있으니 Optional.ofNullable() 함수로 리턴값을 감싸준다
    • public Optional<Member> findByName(String name) : 이름으로 회원 검색(Read)
      • java8의 람다 함수 사용 : 변수.values().stream().filter()
      • member 중에 이름이 같은 것이 있는지 찾기 : .filter(member -> member.getName().equals(name))
      • 찾은 것 중에 아무거나 리턴 : .findAny()
    • public List<Member> findAll() : 모든 회원 리스트(Read)
      • 회원 값을 모두 읽는 함수 : store.values()
      • ArrayList 형식으로 반환 : new ArrayList<>(store.values())

회원 리포지토리 테스트 케이스 작성

JUnit을 사용해 테스트 케이스 작성함

  • 테스트 할 main의 클래스와 같은 폴더구조로 만들고 이름은 클래스 이름 + Test로 작성
  • 테스트 클래스끼리 객체를 분리해서 써야 함
    • 테스트가 끝나고 객체를 리셋해주자
      • repository 구현체(클래스)에서 store를 리셋해주는 함수 만들기
        public void clearStore(){
            store.clear();
        }
      • 테스트 클래스에 @AfterEach가 붙은 함수를 만들어서 위에서 만든 함수 가져와서 쓰기
        @AfterEach
        public void afterEach(){
            repository.clearStore();
        }

회원 서비스 개발

  • 서비스 함수명들은 이름을 잘 지어둬야 기획자 등과 얘기할 때 헷갈리지 않음!
  • 조건문이 들어가는 경우에 따로 메소드를 만들어 리팩토링하자

회원 서비스 테스트

  • 테스트 코드의 메소드 이름은 한글로 적어도 됨!

  • 테스트 코드 작성할 때 given, when, then 으로 작성하면 편함

    • given : 뭔가 주어졌을 때
    • when : 이걸 실행할 때
    • then : 결과가 이렇게 나와야 함
  • 테스트는 예외 처리가 잘 되는 지 검증하는 게 중요함!

  • 서비스를 테스트 할 때에도 repository 데이터를 리셋해줘야 함

    • 그런데 서비스 내부에 repository를 정의해둠

    • 테스트 할 때 또 repository를 만들 이유가 없음

    • memberRepository를 constructor로 만들자

      • MemberService 내부에서 repository를 만들지 않고 외부에서 생성해주도록 하는 것
    • test code에서 @BeforeEach로 memory 인스턴스 생성 후 service 생성할 때 memory 인스턴스를 전달해줌

    • 이런걸 Dependency Injection 이라고 함

      • service

        private final MemberRepository memberRepository;
         public MemberService(MemberRepository memberRepository) {
            this.memberRepository = memberRepository;
        }
      • test

        MemberService memberService;
         MemoryMemberRepository memberRepository;
        
         @BeforeEach
         public void beforeEach(){
            memberRepository = new MemoryMemberRepository();
            memberService = new MemberService(memberRepository);
        }

*. import할 때 단축키 : alt+enter

*. 리턴값의 변수형과 이름을 자동으로 만들어주는 단축키 : ctrl+alt+v

*. 블록 지정한 줄을 메서드로 바꾸는 단축키(리팩토링) : ctrl+alt+shift+t

*. 작성한 클래스의 테스트 파일 만드는 단축키 : ctrl+shift+t

*. 변수명 변경 : shift+f6

0개의 댓글