TIL - 2022

TIL 20220720 (@Builder, DTO, @DynamicInsert, Enum, @Service, Swagger, pipenv)

바랄 희 2022. 7. 21. 22:14

@Builder

객체의 생성에는 두 가지의 패턴이 존재한다. 

하나는 생성자 패턴, 두번쨰는 빌더 패턴이다. 생성자 패턴은 흔히 아는 Contructor 에 해당한다.

@Getter
@Setter
public class Car{
	private String id;
	private String name;

	public Car(String id, String name){
				this.id = id;
				this.name = name;
	}
}

 

 

이에 대한 객체는 아래와 같이 구현된다.

public class CarImpl {

    private String id = "1";
    private String name = "carTest";

    Car car1 = new Car(id, name);
    Car car2 = new Car(name, id);
}

 

반면 Builder 를 이용한 방식은 아래와 같이 작성한다. 

@Builder
    public Item(
            String name,
            int deposit,
            LocalDateTime startDate,
            LocalDateTime endDate,
            LocalDateTime duration,
            int rentalFee,
            Category category

            ){
        this.id = id;
        this.name = name;
        this.deposit = deposit;
        this.startDate = startDate;
        this.endDate = endDate;
        this.duration = duration;
        this.rentalFee = rentalFee;
        this.category = category;
    }

 

이에 대한 객체는 아래와 같이 생성한다

 

public void saveItem(ItemDto itemDto){
        Item item= Item.builder()
                .name(itemDto.getName())
                .deposit(itemDto.getDeposit())
                .startDate(itemDto.getStartDate())
                .endDate(itemDto.getEndDate())
                .duration(itemDto.getDuration())
                .rentalFee(itemDto.getRentalFee())
                .category(itemDto.getCategory())
                .build();
    }

 

 😾 Builder 패턴의 장점

생성자 패턴이 아닌 Builder 패턴을 사용하는 이유는 생성자 패턴은 어떤 파라미터가 어떻게 전달되었는지 확인하기가 어렵다. 반면 빌더 패턴의 경우에는, 

1. 어떤 필드에 어떤 값을 채워야 할지 명확하게 지정할 수 있고, 

2. 생성자 방식보다 가독성이 좋으며

Item item = new Item("전기난로",1000,300);
Item item = Item.builder()
			.name("전기난로")
            .price(1000)
            .rentalFee(300).build();

파라미터 값에 무엇이 들어가는지 한눈에 파악할 수 있음

 

3. 자바빈 패턴보다 안전하면서 (setter를 사용하지 않으니까)

4. 객체를 변경할 수 없는 불변성을 보장하기 때문이다.

 

그 이외에도

5. 필요한 데이터만 설정할 수 있음

ex) 예를 들어서 필요 없는 파라미터가 있는 경우 빌더패턴을 사용하지 않으면 객체를 생성해야 하기 때문에 더미 값을 넣거나 해당 파라미터를 필요로 하지 않는 생성자를 다시 만들어주어야 한다. 그러나 빌더를 이용하면 이가 동적으로 처리된다.

 

6. 유연성이 확보된다

ex) 새로운 변수를 추가해야 하는 경우, 기존의 코드를 전부 수정해야 할 수도 있다. 그러나 빌더 패턴을 이용하여 코드를 짰다면, 기존의 코드를 수정하지 않고도 변수를 추가할 수 있다.

 

DAO vs DTO

DAO

- 데이터베이스의 데이터에 접근하기 위한 객체

- 사용자가 필요한 인터페이스를 DAO 에 던지면 DAO 는 해당 인터페이스를 구현한 객체를 반환

- 데이터베이스에 접속해서 비즈니스 로직 실행에 필요한 쿼리를 호출함

 

DTO

- 계층 간 데이터 교환을 위한 빈즈

- 레코드의 데이터를 매핑하기 위한 데이터 객체

- 로직이 없고 getter 와 setter 만 존재

=> service 나 Controller 로 보낼 때 사용하는 객체

 

@Getter
public class ItemDto {

    @NotBlank
    String name;

    int deposit;

    LocalDateTime startDate;

    LocalDateTime endDate;

    LocalDateTime duration;

    int rentalFee;

    Category category;

    @Builder
    public ItemDto(
            String name,
            int deposit,
            LocalDateTime startDate,
            LocalDateTime endDate,
            LocalDateTime duration,
            int rentalFee,
            Category category
    ){
      this.name = name;
      this.deposit = deposit;
      this.startDate = startDate;
      this.endDate = endDate;
      this.duration = duration;
      this.rentalFee = rentalFee;
      this.category = category;
    }
}

 

DTO를 사용하는 이유는 각 dto에 필요한 데이터만 정의되어야 하고, 필수 값에 대한 조건 체크나 dto에서 domain 으로 변환하거나 그 반대인 로직은 domain이 아닌 dto에 담겨야 한다.

 

😾 DTO의 필요성

1. 데이터를 묶어서 하나의 요청으로 보내면 검증과 로직 처리를 한번에 할 수 있음

2. 안전성 / 수행시간 측면에서 유리

 

+

Controller : View 에서 들어온 사용자의 요청을 해석 => Model 업데이트 / Model에서 데이터를 받아서 View 로 전달.

MVC 패턴에서 이와 같이 Model과 View 를 분리해서 독립적인 개발을 가능하도록 함.

Controller 와 View 사이에서는 데이터를 주고 받을 때 DTO 를 사용함.

직접 도메인의 객체를 View에 전달할 수도 있음. 그러나 그럴 경우에는 도메인 비지니스 기능이 노출될 수 있고, Model 과 View 사이의 의존성이 생기기 때문에 dto 를 사용해야 함.

dto가 존재하지 않으면 UI 단에서 Model의 메서드를 호출하거나 변경할 수 있는 가능성이 존재

 

📌 정리

정리해보자면 DTO는 클라이언트 요청에 포함된 데이터를 담아 서버 측에 전달 / 서버 측의 응답 데이터를 담아 클라이언트에 전달하는 계층간 전달자 역할

 

 

참고

 

@DynamicInsert

JPA의 구현체인 하이버네이트는 INSERT와 UPDATE시에 모든 컬럼을 사용

 


@DynamicInsert는 INSERT 구문 생성 시점에 null이 아닌 컬럼들만,
@DynamicUpdate는 UPDATE구문 생성 시점에 null이 아닌 컬럼만(변경된 값만) 반영된다.

 

ENUM 값을 Column에 저장하기

 

Enum을 이용해서 도메인을 구성하는게 생각보다 헷갈리고 어려웠다.

 

도메인

@NoArgsConstructor
public class Item{
	private Category category;}
// .. 생략
ublic enum Category{
		CLOTHE, COSMETIC}

 

Enum 을 사용하는 필드의 이름을 키값, Enum 클래스에 선언된 상수값을 value 로 전달하면 됨.

 

나중에는 이 글도 읽어봐야지..

https://techblog.woowahan.com/2527/

 

Java Enum 활용기 | 우아한형제들 기술블로그

{{item.name}} 안녕하세요? 우아한 형제들에서 결제/정산 시스템을 개발하고 있는 이동욱입니다. 이번 사내 블로그 포스팅 주제로 저는 Java Enum 활용 경험을 선택하였습니다. 이전에 개인 블로그에 E

techblog.woowahan.com

 

@Service

Spring에서 관리하는 객체임을 나타내는 @Component 와 큰 차이는 없다.

그러나 스프링 공식문서에 따르면

 

비즈니스 로직을 보유하고 있음을 나타내는 데 사용된다는 사실 외에는 이 주석에서 눈에 띄는 것이 없습니다. 그러나 Spring은 미래에 예외적인 기능을 추가할 수 있습니다.

 

라고 한다.

 

Swagger 장고 연결

장고로 진행하고 있는 프로젝트에서 초기 세팅을 해볼 일이 생겨서 swagger 도 찾아봤다.

우선, swagger 는 Open APi Specification (OAS)를 위한 프레임워크이고, API 들이 가지고 있는 스펙을 명세 및 관리할 수 있는 문서이다. 즉 API 사용 방법을 사용자에게 알려주는 문서 역할을 한다.

 

https://velog.io/@max-sum/Django-Swagger-%EA%B8%B0%EB%B3%B8%ED%8E%B8

 

Django + Swagger 기본 사용법

장고랑 스웨거랑

velog.io

 

위 링크를 따라서 swagger 연결을 해줬다

 

 

pipenv

 

pipenv 를 이용하면 requirements.txt 나 setup.py 를 사용해서 표준화가 모호 => 라이브러리로 패키지 관리

 

https://www.daleseo.com/python-pipenv/

 

pipenv로 패키지 관리하기

Engineering Blog by Dale Seo

www.daleseo.com