Spring 객체 지향 원리 적용

강정우·2023년 8월 30일
0

Spring-boot

목록 보기
2/73
post-thumbnail

요구사항 설계

  • 요구사항
  1. 회원 가입하고 조회할 수 있다.
  2. 회원은 일반, VIP가 있다.
  3. 회원 데이터는 자체 DB를 구축할 수 있고 혹은 외부 시스템과 연동할 수 있다.(미확정)
  • 위 요구사항이 들어왔을 때 유능한 개발자는 바로 어떻게 설계할지 떠올릴 수 있어야 한다.

  • 바로 이런식으로
    그리고 참고로 굳이 회원 객체 다이어그램이 존재하는 이유는 위 클래스 다이어그램만을 보고는 실제 spring이 떠서 해당 저장소에 어떤 구현체가 쓰일지는 그때 정해지는 것이기 때문에 클래스 다이어그램만으로는 전체 프로젝트 구조를 파악하는데 한계가 있기 때문에 별도로 객체 다이어그램이 존재한다.

generate

  • alt + insert : generate
  • 참고로 설정 들어가서 keymap 들어간 다음 찾고싶은 명령어 검색하면 옆에 단축키 뜸

HashMap Vs ConcurrentHashMap In Java

  1. Thread Safe
    주요 차이점은 ConcurrentHashMap은 내부적으로 동기화되어 스레드로부터 안전하다는 것. HashMap은 Collections.synchronizedMap() 메서드를 사용하여 외부적으로 동기화할 수 있다.

  2. Internal Structure
    ConcurrentHashMap의 모든 작업이 동기화되는 것은 아니다. 추가 및 삭제와 같은 수정 작업만 동기화되고 읽기 작업은 동기화되지 않는다.
    HashMap을 Collections.synchronizedMap() 메서드를 사용하여 외부에서 동기화하는 경우, 모든 작업이 동기화 된다. 이렇게 하면 속도가 느려지는 문제가 있다.

  3. Introduction Into Java Collection Framework
    HashMap은 JDK 1.2 부터 Java Collection Framework에 포함되었고, ConcurrentHashMap은 나중에 Java Collection Framework에 동시성 패키지의 일부로 도입 되었음. ConcurrentHashMap은 레거시 클래스인 HashTable의 대안으로 취급된다. (HashTable 클래스의 메서드에는 synchronized 키워드 사용하고 있어 스레드 세이프하지만, 속도 저하 이슈가 있음.)

  4. Null Keys And Null Values
    HashMap은 하나의 null 키와 여러 null 값을 허용한다.
    ConcurrentHashMap은 null 키와 null 값을 허용하지 않는다.

  5. Fail-Fast Vs Fail-Safe
    HashMap의 Iterator는 fail-fast 방식을 사용. Iterator가 생성된 이후 Map이 수정되면 즉시 ConcurrentModificationException 예외가 발생하여 프로그램이 중단된다.
    ConcurrentMap의 Iterator는 fail-safe 방식을 사용. Iterator가 생성된 이후 Map이 수정되어도 예외가 발생하지 않는다. Iterator가 반환하는 값은 Iterator가 생성된 시점에서의 Map 상태를 기반으로 하기 때문에 항상 일관된 값을 반환한다. 즉, 수정된 값을 반영하지 않는다.

  6. Performance
    ConcurrentHashMap의 수정 작업만 동기화 된다. 따라서 ConcurrentHashMap의 추가 또는 삭제 작업은 HashMap 보다 느리다.
    읽기 작업은 HashMap과 ConcurrentHashMap 모두 동기화하지 않기 때문에 동일한 성능을 보인다.

  7. When To Use What?
    HashMap은 내부에서 동기화를 제공하지 않기 때문에 단일 스레드(single-threaded) 애플리케이션에 적합하다.
    ConcurrentHashMap은 내부에서 동기화(synchronization)를 제공하여 여러 개의 스레드가 동시에 맵에 접근하고 수정할 수 있도록 하기 때문에 동시 다중 스레드(concurrent multi-threaded) 애플리케이션에 적합하다.

Impl

  • implement된 class를 뜻하는 것으로 통상 정해진 interface의 구현체가 단 1개 존재할 때 통상 그 구현체는 interface명+impl 이라는 명을 conventinal하게 붙인다.

단일 책임원칙을 지킨 좋은 예

public class OrderServiceImpl implements OderService {

    private final MemberRepository memberRepository = new MemoryMemberRepository();
    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice);
        return new Order(memberId, itemName, itemPrice, discountPrice);
    }   
}
  • OderService를 기준으로 봤을 때 사실 discountPolicy.discount는 뭐 사실 내 알빠아니고 그냥 interface의 .discount를 implement한 너의 로직의 결과만 내놔! 라는게 되기 때문에 추후 할인 정책이 바뀌어도 어차피 discount 메서드는 살아있을 것이고 정책에 해당하는 로직만 바꿔서 치환해주면 되기 때문에 결합도가 떨어져서 단일 책임원칙을 잘 지킨 예라고 볼 수 있다.

  • 참고로 저기 discount에서 현재 필요한 로직은 VIP 즉, Grade밖에 없지만 미래 확장성 때문에 member 데이터를 통으로 넘긴 것이다.

단위 테스트가 또 중요한 점

  • 위 사진을 보면 2개의 Test 파일을 볼 수 있고 CoreApplicationTests라는 파일을 또 볼 수 있다. 해당 파일은 Spring initalizer를 통해 생성할 때 자동으로 만들어지는 파일로 해당 파일을 실행하면 Spring 띄우는 것 부터 시작해서 매우 오래 기다려야하지만 unit test는 수천개라도 JAVA로만 돌려서 몇 초만에 끝나기 때문에 속도 측면에서 그래서 단위테스트를 잘 사용하는 것이 좋다고 하는 것이다.

단위 테스트 빠르게 생성하는 법

  • 단축키 window : ctrl + shift + T, mac : cmd + shift + T

  • 그리고 이때 JUnit 5(23.08.30)를 사용하는 것이 좋다.

  • 또한 성공테스트도 중요하지만 실패 테스트 케이스도 다양하게 해보는 것이 매우 중요하다.

  • 또한 mac : opt + enter, window : alt + endter로 static하게 import하는 것이 훨씬 편리하고 개발속도를 조금 올려줄 수 있다.

오류

  • 대충 읽어보니 영한쌤 강의는 JAVA 11에 의존한다고 하였는데 시간이 지나 스프링이 업데이트 되면서 18년도 구시대 JAVA11은 호환이 안 된다고 적혀있었다.

  • 하지만 걱정말라 Gradle의 자바 버츄얼 머신을 업그레이드해주면 된다. 아래와 같에 셋팅에서 버전을 다시 잡아주고

  • 뭐 build.gradle 회오리 버튼을 누르든 아래 build 창에서 새로고침을 누르든 누르면

  • 짜잔~ 해결되었다.
  • 그리고 기왕 setting (preference) 를 들어간 김에 단축키(window: ctrl alt s, mac: via cmd) Build and Run 부분을 모두 Gradle -> IntelliJ로 바꿔주면 intelli가 gradle을 통하여 실행하는 것을 intelli가 바로 실행하기 때문에 조금 더 빠르다고 한다.

reference

profile
智(지)! 德(덕)! 體(체)!

0개의 댓글