스프링의 핵심 컨셉 (항해일지 29일차)

김형준·2022년 6월 6일
0

TIL&WIL

목록 보기
29/45

1. 학습 일지


1)스프링 입문 주차 강의

복습

  • @ResponseBody 를 붙이면 return 값은 HTTP Body에 들어간다.

    • 디폴트로 viewResolver 대신 HttpMessageConverter가 동작한다.
      • String 처리: StringHttpMessageConverter
      • 기본 객체 처리: MappingJackson2HttpMessageConverter
      • byte 처리 등 기타 여러 HttpMessageConverter가 기본으로 등록되어있다.
    • 이 때 자바 객체(String 제외)를 return 하면 디폴트로 JSON 형식으로 변환되어 리턴된다.
    • 위 사진에서 보는 것과 같이, String은 StringConverter가, 나머지는 JsonConverter가 변환해주는 것이다.
    • (즉, String을 return하면 JSON형식이 아닌! String 그대로 들어간다.)

  • Test 클래스

    • @AfterEach는 각 테스트 케이스마다 종료시 실행되는 메서드에 붙여주는 어노테이션
      • 강의에서는 같은 변수 명을 사용할 경우, 다른 케이스에 영향을 줄 수 있기에, 이를 방지하고자 clear()를 넣어주기 위해 사용함
    • ** 즉, 테스트 케이스는 독립적으로 실행되어야 하기 때문에! 순서에 관계없이, 서로 의존하지 않도록 설계되어야 한다.
    • @Transactional : 테스트 케이스에 이 애노테이션이 있으면, 테스트 시작 전에 트랜잭션을 시작하고,
    • 테스트 완료 후에 항상 롤백한다. 이렇게 하면 DB에 데이터가 남지 않으므로 다음 테스트에 영향을 주지 않는다.

  • Optional
    • Optional로 받을 시 해당 객체 혹은 null 값으로 들어가있다.
    • Optional이 제공하는 메서드를 사용하면 편리하다.
    • 아래는 isPresent ( Optional에 담긴 값이 null이 아니라면 true를 반환) 를 사용하여 예외처리한 코드.
        Optional<Member> result = memberRepository.findByName(member.getName());
        result.ifPresent(m -> {
            throw new IllegalArgumentException("이미 존재하는 회원입니다.");
        });

  • ThymeLeaf ForEach 문법 (html)
<tbody>
    <tr th:each="member : ${members}">
        <td th:text="${member.id}"></td>
        <td th:text="${member.name}"></td>
    </tr>
</tbody>

  • 순수 JPA 사용법
    • Repository에서 EntityManager를 DI 해야한다.
    • 이 후 모든 메서드는 EntityManager를 통해서 구현한다.
    @Override
    public Member save(Member member) {
        em.persist(member);
        return member;
    }
  • 만약 EntityManager가 기본적으로 제공하는 메서드 외의 쿼리를 구현해야 한다면, jpql을 사용해야한다.
  • 사용 방법은 아래와 같다.
    @Override
    public Optional<Member> findByName(String name) {
        List<Member> result = em.createQuery("select m from Member m where m.name = :name", Member.class)
                .setParameter("name", name)
                .getResultList();
        return result.stream().findAny();
    }

Spring Data JPA 상속 구조

  • 출처 : 김영한 님의 스프링 입문 강의

2) 스프링의 진짜 핵심

  • 스프링은 자바 언어 기반의 프레임워크
  • 자바 언어의 가장 큰 특징은 객체 지향 언어
  • 스프링은 객체 지향 언어가 가진 강력한 특징을 살려내는 프레임워크
  • 💥스프링은 좋은 객체 지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크

3) 좋은 객체 지향 프로그래밍?

  • 객체 지향의 특징: 추상화, 캡슐화, 상속, 다형성..
  • 그 중 다형성은 유연하고 변경이 용이하다 라는 장점으로 이어진다.
    • 즉, 컴포넌트를 쉽고 유연하게 변경하면서 개발할 수 있는 방법
    • 다형성을 실세계에 비유하자면 역할구현으로 볼 수 있다. (역할 = 인터페이스, 구현 = 구현체)

  • 운전자는 자동차의 역할에 대해서만 알고 있다.
  • 즉, 실제 자동차 구현체의 내부 구조는 모르며, 자동차 구현체라면 꼭 구현해야하는 역할을 알고 있는 것.
  • 따라서 운전자는 실제 자동차 구현체인 k3, 아반떼, 테슬라 등 어떤 자동차가 와도 운전을 할 수 있다.
  • 새로운 기능을 가진 자동차가 나와도 클라이언트는 이를 사용할 수 있다. (확장성을 보장해준다.)
  • 이를 유연하고 변경이 용이하다고 하는 것이다!

다형성 핵심

  • 클라이언트는 대상의 역할(인터페이스)만 알면 된다
  • 클라이언트는 구현 대상의 내부 구조를 몰라도 된다
  • 클라이언트는 구현 대상의 내부 구조가 변경되어도 영향을 받지 않는다
  • 클라이언트는 구현 대상 자체를 변경해도 영향을 받지 않는다
    -> 객체 설계시 역할(인터페이스)을 먼저 부여하고, 그 역할을 수행하는 구현 객체 만들기
  • 자바 언어의 다형성은 오버라이딩으로 구현된다. (물론 그 외에 상속과 같은 다른 방법도 존재)

  • 다형성의 본질

    • 인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경 가능하다.
    • 클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있다.
  • 결론: 💥 인터페이스를 안정적으로 잘 설계하는 것이 중요하다!


4) SOLID

  • 클린코드로 유명한 로버트 마틴이 좋은 객체 지향 설계의 5가지 원칙을 정리한 것이다.

    요약

    • SRP: 단일 책임 원칙(single responsibility principle) :
      • 한 클래스는 하나의 책임만 가져야 한다
      • 중요한 기준은 변경이다. 변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것
    • OCP: 개방-폐쇄 원칙 (Open/closed principle)
      • 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다
      • 💥 하지만 자바의 다형성에만 충실하게 코드를 작성하면 이를 위반할 수 밖에 없게 된다.
      • 예를 들어 서비스에서 인터페이스를 필드에 가지고 있을 경우, 이에 할당할 값을 new 연산자로 준다면 새로운 구현체가 나올 때마다 계속해서 변경해줘야 한다.
public class MemberServiceTest {

    // 의존관계가 인터페이스 뿐만 아니라 구현까지 모두 의존하는 문제점이 있다.
    // 즉, 추상화에도 의존하고 구체화에도 의존하고 있어, SOLID의 OCP, DIP 에 어긋난다.
    MemberService memberService = new MemberServiceImpl();
	...
  • LSP: 리스코프 치환 원칙 (Liskov substitution principle)
    • 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다
    • 다형성 하위 클래스는 인터페이스 규약을 지켜야한다는 것!
  • ISP: 인터페이스 분리 원칙 (Interface segregation principle)
    • 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다
    • 인터페이스의 스코프를 세분화하여 명확하고, 대체 가능성이 높게 설계하자는 뜻이다.
  • DIP: 의존관계 역전 원칙 (Dependency inversion principle)
    • 추상화에 의존해야지, 구체화에 의존하면 안된다는 원칙
    • 💥 위 OCP 원칙의 경우와 같이, new 연산자로 할당하는 경우 인터페이스(추상화) 뿐만 아니라 구현체(구체화)에도 의존을 하게 된다.

✨✨✨스프링은 이러한 객체지향이 지니는 한계점을 보완해준다!✨✨✨

  • DI, DI컨테이너 제공 등을 통해 다형성 + OCP, DIP를 가능하게 지원해준다.
  • 클라이언트 코드의 변경 없이 기능 확장

2. 코멘트

  • 오늘은 인프런_김영한님의 스프링 입문 강의를 수강했다.
  • 전체적인 스프링 부트 프로젝트를 간단히 구현해보며 리마인드 할 수 있었다.
  • 앞으로 남은 기간 동안 학습해야할 부분들을 간단히 추려서 로드맵을 계획했고, 플렉스했다. 미래를 위한 투자는 아끼지 말자! 어차피 평생수강이니 지금 당장 이해 안가더라도 나중에는 이해 가겠지!
  • 스터디 팀원분과 일요일에 구현했던 과제를 공유하던 중에 @JoinColumn의 기능을 제대로 파악하게 됐다.
    • @JoinColumn을 사용하지 않으면 DB에는 각 테이블에 서로에 대한 정보가 저장되지 않고 새롭게 연관관계를 담은 테이블이 생성된다.
    • 만약 @JoinColumn을 사용한다면, 각 객체의 테이블에 Foreign Key를 저장하는 column이 생성되며 연관관계 테이블이 생성되지 않는다.
    • 어떤 방식이 더 좋은지는 모르겠으나 일단 @JoinColumn을 사용하여 DB 테이블 수가 지저분하게 많아지는 것을 막기로 결정했다.
  • 내일 할 것 + 1
  • 오늘도 고생했고, 내일도 화이팅!!!!!!!!!!!🎉
profile
BackEnd Developer

0개의 댓글