원지의 개발
article thumbnail
728x90

1. 생성

1.1. JPA

  • EJB 엔티티빈(사용 어려움)이 등장 후 하이버네이트가 나왔고, 표준으로 JPA가 됨
  • JPA는 표준 인터페이스이고 구현체로 하이버네이트, EclipseLink 등이 있음

1.2. 스프링

  • 로드 존슨
  • EJB의 문제점 지적 후 생긴 기술

2. 스프링 프레임워크

  • 핵심 기술: 스프링 DI 컨테이너, AOP, 이벤트, 기타
  • 좋은 객체 지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크
  • 웹기술: 스프링 MVC, 스프링 WebFlux
  • 데이터 접근 기술: 트랜잭션, JDBC, ORM 지원, XML 지원
  • 기술 통합: 캐시, 이메일, 원격접근, 스케줄링
  • 테스트: 스프링 기반 테스트 지원
  • 언어: 코틀린, 그루비

2.1. 스프링 부트

  • 스프링을 편하게 사용할 수 있도록 지원
  • 단독으로 실행할 수 있는 스프링 애플리케이션을 쉽게 생성 (톰캣 내장)
  • 손쉬운 빌드 구성을 위한 starter 종속성 제공 (AOP, Data-JPA 등 알아서 라이브러리 땡겨옴)
  • 스프링과 3rd party(외부) 라이브러리 자동 구성
  • 모니터링 해줌

2.2. 객체 지향 프로그래밍

  • 역할(인터페이스)과 구현(구현한 클래스, 구현 객체)을 분리하면 유연해지며, 변경도 편리해짐
  • 객체는 협력이라는 관계부터 생각 (혼자 있는 객체는 X)
  • 클라이언트: 요청, 서버: 응답
  • 다형성: 클라리언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있음

3. 실습 - 비즈니스 요구사항과 설계

  • 비즈니스 요구 사항 설계시 회원 저장소가 미정된 상태로 우선 개발 진행
  • 역할과 구현을 나눠서 인터페이스를 만들고, 구현체를 언제든지 갈아 끼울 수 있게 만들어야 함
  • 실습은 스프링 사용 없이 개발 진행

4. 1. 회원 도메인

4.1. 설계

4.1.1. 1. 전체적인 도메인 그림

  • 역할로써 클라이언트 - 회원 서비스 - 회원 저장소로 분리
  • 그중에서 회원 저장소(역할)는 나중에 어떻게 될 지 모르기 때문에 인터페이스로 만들고, 우선 메모리 회원 저장소(컴퓨터 재부팅 시 삭제)로 구현해서 사용 하다가 확정되면 갈아 끼울 수 있게 만듦

4.1.2. 2. 클래스 다이어그램

  • 정적
  • 멤버서비스 인터페이스(역할) 만든 후, 회원 서비스는 회원가입, 회원조회만 하니까 implements 받아서 구현하기

4.1.3. 3. 객체 다이어그램

  • 동적 (실행했을 때 어떻게 되는지)
  • 애플리케이션을 띄워서 동적으로 객체들의 연관관계가 맺어지는 그림
  • 클래스 다이어그램으로 알 수 없는 부분 (예를 들어 저장소는 실행 후 동적으로 동작되기 때문에)이 있으므로 실제 실행되는 인스턴스의 설계

4.2. 개발

  • 인터페이스와 구현체를 다른 패키지에 놓는 게 설계상 좋음
  • 등급은 Enum, 사용자(멤버)는 class로 만들기
  • 역할로 MemberRepository(인터페이스) 만들고 save 저장 기능, findById 조회 기능
  • implements 받아서 구현해야하는데 저장소이기 때문에 
<java />
private static Map<Long, Member> store = new HashMap<>(); //실무에서는 동시성 이슈로 ConcurrentHashMap 써야 함
  • 구현체가 없이 null 이면 터지므로 구현체로 MemoryMemberRepository 만들기

4.3. 실행 및 테스트

<java />
package hello.core.member; import static org.junit.jupiter.api.Assertions.*; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; 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.assertThat(member).isEqualTo(findMember); } }
<java />
package hello.core.member; public class MemberApp { public static void main(String[] args) { MemberService memberService = new MemberServiceImpl(); Member member = new Member(1L, "memberA", Grade.Vip); memberService.join(member); Member findMember = memberService.findMember(1L); //제대로 동작한다면 저장한 member == 찾은 findMember System.out.println(member); System.out.println(findMember); } }
  • MemberApp 클래스는 순수 자바코드로 확인
  • 문제점
    MemberServiceImpl 클래스에서
    인터페이스(MemberRepository)는 의존하지만 구현체(MemoryMemberRepository)까지 의존하게 됨
    추상화, 구체화 둘 다에 의존 -> DIP 위반
  • org.assertj.core.api.Assertions는 메서드 체이닝 지원하기 때문에 문자와 숫자를 비교할 때도 가독성이 좋음
Method chaining 메서드 체이닝
: 하나의 객체에 대해 연속적으로 여러 메서드를 호출하는 것
체인내의 각 메서드는 이전 메서드를 기반으로 동작하고, 다음 메서드를 호출
동일한 객체 참조를 반복하지 않고도 동일한 객체에 대해 여러 어셔션 수행 가능
<java />
import static org.assertj.core.api.Assertions.assertThat; public class ExampleTest { public void testExample() { String text = "안녕, 세계!"; // 메서드 체이닝을 사용한 어서션 assertThat(text) .isNotNull() .startsWith("안녕") //시작이 "안녕"인가? .endsWith("세계!") //끝이 "세계!"인가? .hasSize(8); //text 길이가 8인가? } }

 

728x90
profile

원지의 개발

@원지다

250x250