BackEnd๐ŸŒฑ/Etc

๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์™€ ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ

์•ˆ์ฃผํ˜• 2024. 6. 18. 00:33

๊ฐœ์š”

์†Œํ”„ํŠธ์›จ์–ด ์•„ํ‚คํ…์ฒ˜์—์„œ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์™€ ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•œ ์„ค๊ณ„ ์›์น™ ์ค‘ ํ•˜๋‚˜์ด๋‹ค. ์ด ์›์น™์€ ํด๋ฆฐ ์•„ํ‚คํ…์ฒ˜์˜ ํ•ต์‹ฌ ๊ฐœ๋…์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋ฉฐ, ๋„๋ฉ”์ธ ๋กœ์ง๊ณผ ์˜์†์„ฑ ๊ณ„์ธต ๊ฐ„์˜ ์˜์กด์„ฑ์„ ์ตœ์†Œํ™”ํ•˜์—ฌ ์‹œ์Šคํ…œ์˜ ์œ ์ง€ ๋ณด์ˆ˜์„ฑ๊ณผ ํ™•์žฅ์„ฑ์„ ๋†’์ด๋Š” ๋ฐ ๋ชฉ์ ์ด ์žˆ๋‹ค.

์ด๋ฒˆ ๊ฒŒ์‹œ๊ธ€์—์„œ๋Š” ์ด๋Ÿฌํ•œ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์™€ ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ์˜ ์ฐจ์ด์ ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ณ , ์ด ๋‘˜์„ ๋ถ„๋ฆฌํ•จ์œผ๋กœ์จ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์ด์ ๊ณผ ์ฃผ์˜ํ•ด์•ผ ํ•  ์  ๊ทธ๋ฆฌ๊ณ  ์–ธ์ œ ๋ถ„๋ฆฌํ•˜๋ฉด ์ข‹์„์ง€์— ๋Œ€ํ•ด ์ •๋ฆฌํ–ˆ๋‹ค.

 

 

๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ

๋จผ์ € ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์˜ ๊ฐœ๋…๋ถ€ํ„ฐ ์‚ดํŽด๋ณด๋ฉด ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋„๋ฉ”์ธ ๋‚ด์˜ ๊ฐœ๋…์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐ์ฒด๋กœ, ์ „์ž์ƒ๊ฑฐ๋ž˜ ์‹œ์Šคํ…œ์—์„œ๋Š” 'Order', 'Customer', 'Product'๋“ฑ์ด ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ์€ ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ ์ฝ”๋“œ์ด๋‹ค.

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class Order {
    private String orderId;
    private Address shippingAddress;
    private List<OrderItem> items;
    private OrderStatus status;

    public Order(String orderId, Address shippingAddress, List<OrderItem> items) {
        this.orderId = orderId;
        this.shippingAddress = shippingAddress;
        this.items = new ArrayList<>(items);
        this.status = OrderStatus.PENDING;
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Order order = (Order) o;
        return orderId.equals(order.orderId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(orderId);
    }
}
import java.util.Objects;

public class Address {
    private final String street;
    private final String city;
    private final String zipcode;

    public Address(String street, String city, String zipcode) {
        this.street = street;
        this.city = city;
        this.zipcode = zipcode;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Address address = (Address) o;
        return Objects.equals(street, address.street) && Objects.equals(city, address.city) && Objects.equals(zipcode, address.zipcode);
    }

    @Override
    public int hashCode() {
        return Objects.hash(street, city, zipcode);
    }
}

์œ„ ์ฝ”๋“œ์—์„œ Address๋Š” Value Object๋กœ, ์—”ํ‹ฐํ‹ฐ์™€ ๋‹ฌ๋ฆฌ ๊ณ ์œ  ์‹๋ณ„์ž๊ฐ€ ์—†์œผ๋ฉฐ ์†์„ฑ๋งŒ์œผ๋กœ ๋™์ผ์„ฑ์„ ํŒ๋‹จํ•œ๋‹ค. ์ด๋Š” ๋ถˆ๋ณ€(immutable) ๊ฐ์ฒด๋กœ ์ฃผ๋กœ ๊ฐ’ ํƒ€์ž…์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ๋ฐ˜๋ฉด Order๋Š” ๊ณ ์œ ํ•œ ์‹๋ณ„์ž์ธ orderId๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์ด ์‹๋ณ„์ž๋ฅผ ํ†ตํ•ด ์—”ํ‹ฐํ‹ฐ ๊ฐ„์˜ ๋™์ผ์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค. ์ด๋ฅผ ์ž˜ ๋ณด์—ฌ์ฃผ๋Š” ๋ถ€๋ถ„์ด equals์™€ hashCode ๋ฉ”์„œ๋“œ์˜ ๊ตฌํ˜„ ๋ถ€๋ถ„์ธ๋ฐ, ์—”ํ‹ฐํ‹ฐ๋Š” ID๋งŒ ๋น„๊ตํ•˜๊ณ , VO๋Š” ๋ชจ๋“  ์†์„ฑ์„ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๋˜ํ•œ import ๋ถ€๋ถ„์„ ๋ณด๋ฉด ์ˆœ์ˆ˜ POJO๋กœ ๊ตฌ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ

๊ทธ๋ ‡๋‹ค๋ฉด ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋Š” ์–ด๋–จ๊นŒ? ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ๋˜๊ณ  ORM์„ ํ†ตํ•ด ๊ด€๋ฆฌ๋˜๋Š” ๊ฐ์ฒด์ด๋‹ค. ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”๊ณผ 1:1๋กœ ๋งคํ•‘๋˜๋ฉฐ ์ฃผ๋กœ JPA ๊ฐ™์€ ORM ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ์ž‘์šฉํ•œ๋‹ค. ๋‹ค์Œ์€ ๊ฐ„๋‹จํ•œ ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ ์˜ˆ์‹œ์ด๋‹ค.

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import jakarta.persistence.*;

@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long orderId;

    @Embedded
    private Address shippingAddress;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "order_id")
    private List<OrderItem> items;

    @Enumerated(EnumType.STRING)
    private OrderStatus status;

    protected Order(){
    }

    public Order(Address shippingAddress, List<OrderItem> items) {
        this.shippingAddress = shippingAddress;
        this.items = new ArrayList<>(items);
        this.status = OrderStatus.PENDING;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Order order = (Order) o;
        return orderId.equals(order.orderId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(orderId);
    }
 }
 
 // ์ดํ•˜ Address ๋“ฑ ์ƒ๋žต

์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋Š” ์˜์†์„ฑ์„ ์œ„ํ•œ ์–ด๋…ธํ…Œ์ด์…˜๋“ค์ด ๋ถ™์–ด ์žˆ๋‹ค๋Š” ์ ์—์„œ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์™€ ๋‹ค๋ฅด๋‹ค. Order ์—”ํ‹ฐํ‹ฐ๋Š” @Entity ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์ง€์ •๋˜์–ด ์žˆ์œผ๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘๋œ๋‹ค. Address๋Š” @Embeddable ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‚ด์žฅ ํƒ€์ž…์œผ๋กœ ์ •์˜๋˜์—ˆ๊ณ , OrderItem์€ Order์™€ @OneToMany ๊ด€๊ณ„๋ฅผ ๊ฐ–๋Š”๋‹ค.

๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋Š” ์ฃผ๋กœ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํฌํ•จํ•˜๊ณ  ์žˆ์–ด ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™๊ณผ ๋„๋ฉ”์ธ ๊ฐœ๋…์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฐ ์ค‘์ ์„ ๋‘”๋‹ค. ๋ฐ˜๋ฉด ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ์œ„ํ•ด ์„ค๊ณ„๋˜๋ฉฐ, ๋ฐ์ดํ„ฐ ์ €์žฅ๊ณผ ์กฐํšŒ์— ์ค‘์ ์„ ๋‘”๋‹ค. ํ˜„์žฌ ์˜ˆ์‹œ์—์„œ๋Š” ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์™€ ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ์˜ ํ•„๋“œ๋ฅผ ์ „๋ถ€ ๋™์ผํ•˜๊ฒŒ ์ž‘์„ฑํ–ˆ์ง€๋งŒ, ๋ณดํ†ต์˜ ๊ฒฝ์šฐ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋‹ด๊ณ  ์žˆ์–ด ํ•„๋“œ์™€ ๋ฉ”์„œ๋“œ๊ฐ€ ๋” ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์—์„œ๋Š” ์ฃผ๋ฌธ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ํฌํ•จ๋  ์ˆ˜ ์žˆ๋‹ค.

public void completeOrder() {
    if (this.status != OrderStatus.PENDING) {
        throw new IllegalStateException("Order cannot be completed");
    }
    this.status = OrderStatus.COMPLETED;
}

๊ทธ๋Ÿฌ๋‚˜ ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ์™€ ์ผ์น˜ํ•˜๋Š” ํ•„๋“œ์™€ ๋‹จ์ˆœํ•œ CRUD ์ž‘์—…์— ํ•„์š”ํ•œ ๋ฉ”์„œ๋“œ๋งŒ์„ ๊ฐ€์ง€๋ฏ€๋กœ, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋ณด๋‹ค๋Š” ๋ฐ์ดํ„ฐ ์ €์žฅ๊ณผ ์กฐํšŒ์— ๋” ์ง‘์ค‘ํ•œ๋‹ค. ๋ฌผ๋ก , ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋Š” ์ด๋Ÿฌํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ์— ์ž‘์„ฑ๋  ์ˆ˜ ์žˆ๋‹ค.

 

 

์™œ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์™€ ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š”๊ฐ€?

์œ„์˜ ์˜ˆ์‹œ ์ฝ”๋“œ์—์„œ ๋ดค๋“ฏ์ด ๊ตณ์ด ์ด ๋‘˜์„ ๋ถ„๋ฆฌํ•˜์ง€ ์•Š๊ณ  ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋กœ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ๋„ ์™œ ๊ตณ์ด ์ด ๋‘˜์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ผ๊นŒ?

๋จผ์ €, ํด๋ฆฐ ์•„ํ‚คํ…์ฒ˜์˜ ์›์น™์„ ์‚ดํŽด๋ณด์ž. ํด๋ฆฐ ์•„ํ‚คํ…์ฒ˜์—์„œ๋Š” ๋ชจ๋“  ์˜์กด์„ฑ์ด ๋„๋ฉ”์ธ ๋กœ์ง์„ ํ–ฅํ•ด ์•ˆ์ชฝ ๋ฐฉํ–ฅ์œผ๋กœ ํ–ฅํ•œ๋‹ค. ์ด ์•„ํ‚คํ…์ฒ˜๋Š” ๋™์‹ฌ์› ๊ตฌ์กฐ๋กœ ๊ณ„์ธต๋“ค์ด ๋‘˜๋Ÿฌ์‹ธ์—ฌ ์žˆ์œผ๋ฉฐ, ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ทœ์น™์€ ๊ณ„์ธต ๊ฐ„์˜ ๋ชจ๋“  ์˜์กด์„ฑ์ด ์•ˆ์ชฝ์œผ๋กœ ํ–ฅํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

ํด๋ฆฐ ์•„ํ‚คํ…์ฒ˜์—์„œ ๋ชจ๋“  ์˜์กด์„ฑ์€ ๋„๋ฉ”์ธ ๋กœ์ง์„ ํ–ฅํ•ด ์•ˆ์ชฝ ๋ฐฉํ–ฅ์œผ๋กœ ํ–ฅํ•œ๋‹ค.

ํด๋ฆฐ ์•„ํ‚คํ…์ฒ˜์˜ ํ•ต์‹ฌ์—๋Š” ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์žˆ๋‹ค. ์œ ์Šค์ผ€์ด์Šค๋Š” ๋‹จ์ผ ์ฑ…์ž„์„ ๊ฐ–๊ธฐ ์œ„ํ•ด ๋” ์„ธ๋ถ„ํ™”๋œ ํ˜•ํƒœ์˜ ์„œ๋น„์Šค๋กœ ๊ตฌ์„ฑ๋˜๋ฉฐ, ์ด ์ฝ”์–ด๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์„ ๊ตฌํ˜„ํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‹ค๋ฅธ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋“ค์ด ์กด์žฌํ•œ๋‹ค. ์ด ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์˜์†์„ฑ์„ ์ œ๊ณตํ•˜๊ฑฐ๋‚˜ UI๋ฅผ ์ œ๊ณตํ•˜๋Š” ์—ญํ• ์„ ํ•˜๋ฉฐ, ๋ฐ”๊นฅ์ชฝ ๊ณ„์ธต๋“ค์€ ์„œ๋“œํŒŒํ‹ฐ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ์–ด๋Œ‘ํ„ฐ ์—ญํ• ์„ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

๋„๋ฉ”์ธ ์ฝ”๋“œ์—์„œ๋Š” ์–ด๋–ค ์˜์†์„ฑ ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ UI ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํŠน์ • ํ”„๋ ˆ์ž„์›Œํฌ์— ํŠนํ™”๋œ ์ฝ”๋“œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค. ์ด ๋•๋ถ„์— ์˜ค์ง ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ณ , ๋„๋ฉ”์ธ ์ฝ”๋“œ๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๋ชจ๋ธ๋งํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋Š” ๊ณง ๋„๋ฉ”์ธ ์ฃผ๋„ ์„ค๊ณ„(DDD)๋ฅผ ๊ฐ€์žฅ ์ˆœ์ˆ˜ํ•œ ํ˜•ํƒœ๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์™€, ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ถ„๋ฆฌ

๊ฐ€๋ น, ์˜์†์„ฑ ๊ณ„์ธต์—์„œ ORM ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•ด๋ณด์ž. ์ผ๋ฐ˜์ ์œผ๋กœ ORM ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ตฌ์กฐ์™€ ๊ฐ์ฒด ํ•„๋“œ ๋ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์นผ๋Ÿผ ๊ฐ„์˜ ๋งคํ•‘์„ ์„œ์ˆ ํ•œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค๋ฅผ ํ•„์š”๋กœ ํ•œ๋‹ค. ๋„๋ฉ”์ธ ๊ณ„์ธต์€ ์˜์†์„ฑ ๊ณ„์ธต์„ ์•Œ์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋„๋ฉ”์ธ ๊ณ„์ธต์—์„œ ์‚ฌ์šฉํ•œ ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค๋ฅผ ์˜์†์„ฑ ๊ณ„์ธต์—์„œ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๋”ฐ๋ผ์„œ ๋‘ ๊ณ„์ธต์—์„œ ๊ฐ๊ฐ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. ๋„๋ฉ”์ธ ๊ณ„์ธต๊ณผ ์˜์†์„ฑ ๊ณ„์ธต์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ๋•Œ, ๋‘ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์„œ๋กœ ๋ณ€ํ™˜ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋Š” ๋„๋ฉ”์ธ ๊ณ„์ธต๊ณผ ๋‹ค๋ฅธ ๊ณ„์ธต๋“ค ์‚ฌ์ด์—์„œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค.

์ฆ‰, ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์™€ ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ์ด์œ ๋Š” ํด๋ฆฐ ์•„ํ‚คํ…์ฒ˜์˜ ์›์น™์— ๋”ฐ๋ผ ๊ณ„์ธต ๊ฐ„์˜ ์˜์กด์„ฑ์„ ์ตœ์†Œํ™”ํ•˜๊ณ , ๋„๋ฉ”์ธ ๋กœ์ง์ด ํŠน์ • ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ๊ธฐ์ˆ ์— ์ข…์†๋˜์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค. 

 

 

๊ผญ ๋ถ„๋ฆฌํ•ด์•ผ ํ•˜๋Š”๊ฐ€?

๋„๋ฉ”์ธ ๋ชจ๋ธ์€ ์˜์†์„ฑ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ˆœ์ˆ˜ํ•ด์•ผ ํ•˜๋ฉฐ, ์„ค๊ณ„์—์„œ ๋„๋ฉ”์ธ์ด ๊ฐ€์žฅ ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง€๋ฉฐ ์ค‘์‹ฌ์ด ๋œ๋‹ค. ORM์„ ์‚ฌ์šฉํ•˜๋‹ค๊ฐ€ ๋‹จ์ˆœ ์ฟผ๋ฆฌ ์‹คํ–‰๊ธฐ(e.g., JDBC, MyBatis)๋กœ ๋ณ€๊ฒฝํ•ด๋„ ๋„๋ฉ”์ธ ์„ค๊ณ„๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค. ์ฆ‰ ์˜์†์„ฑ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์‚ฌ์šฉ ์—ฌ๋ถ€๊ฐ€ ๋„๋ฉ”์ธ ์˜์—ญ์— ์˜ํ–ฅ์„ ์ฃผ์–ด์„œ๋Š” ์•ˆ ๋œ๋‹ค.

ํ•˜์ง€๋งŒ ์ž˜ ์ƒ๊ฐํ•ด ๋ณด์ž ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ํ•œ ๋ฒˆ ๋„์ž…๋œ ๊ธฐ์ˆ ๋“ค์ด ๋ณ€๊ฒฝ๋œ ์ ์ด ์žˆ๋Š”๊ฐ€? ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์–ด๋–ค ์ ๋“ค์„ ๊ณ ๋ คํ•˜๋ฉด ์ข‹์„๊นŒ? 

  1. ์ผ๋ฐ˜์ ์ธ ๊ทœ๋ชจ์˜ ํ”„๋กœ์ ํŠธ์—์„œ ORM์„ ์‚ฌ์šฉํ•˜๋‹ค๊ฐ€ ๊ฑท์–ด๋‚ธ ์ ์ด ์žˆ๋Š”๊ฐ€?
  2. ๋„๋ฉ”์ธ ๋ชจ๋ธ๊ณผ ORM @Entitiy๋ฅผ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ง€๋Š” ์•Š๋Š”๊ฐ€?
  3. JPA๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค์— jakarta.persistence(java 17 ๋ฏธ๋งŒ์—๋Š” javax)๋งŒ ์ถ”๊ฐ€๋กœ import ํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ์ด๊ฒƒ๋„ ์ˆœ์ˆ˜ POJO๋กœ ๊ฐ„์ฃผํ•  ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ?
  4. ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐ์— ๊ธฐ์ˆ  ์„ ํƒ์„ ์ž˜๋ชปํ•œ ๊ฒฝ์šฐ, ๋‚˜์ค‘์— ์ด๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด ๋“ค์—ฌ์•ผ ํ•  ๋น„์šฉ๊ณผ ๋…ธ๋ ฅ์ด ์–ด๋Š ์ •๋„์ธ๊ฐ€?
  5. ๋„๋ฉ”์ธ ๋ชจ๋ธ๊ณผ ์˜์†์„ฑ ๋ชจ๋ธ์ด ๋ถ„๋ฆฌ๋จ์œผ๋กœ์จ ํŒ€์˜ ๊ฐœ๋ฐœ ์†๋„์™€ ์ฝ”๋“œ ํ’ˆ์งˆ์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์€ ๋ฌด์—‡์ธ๊ฐ€?
  6. ๋„๋ฉ”์ธ ๋ชจ๋ธ๊ณผ ์˜์†์„ฑ ๋ชจ๋ธ์˜ ๋ถ„๋ฆฌ๋ฅผ ํ†ตํ•ด ์–ป์„ ์ˆ˜ ์žˆ๋Š” ํ…Œ์ŠคํŠธ์˜ ์šฉ์ด์„ฑ์€ ์–ด๋Š ์ •๋„์ธ๊ฐ€?
  7. ๋„๋ฉ”์ธ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํŒ€์›์ด๋‚˜ ํ›„์ž„ ๊ฐœ๋ฐœ์ž๊ฐ€ ํ”„๋กœ์ ํŠธ์— ์ฐธ์—ฌํ•  ๊ฒฝ์šฐ, ๋„๋ฉ”์ธ ๋ชจ๋ธ๊ณผ ์˜์†์„ฑ ๋ชจ๋ธ์˜ ๋ถ„๋ฆฌ๋กœ ์ธํ•œ ํ•™์Šต ๊ณก์„ ์€ ์–ด๋–ป๊ฒŒ ๋˜๋Š”๊ฐ€?

์œ„ ์งˆ๋ฌธ๋“ค์€ ๋„๋ฉ”์ธ ๋ชจ๋ธ๊ณผ ์˜์†์„ฑ ๋ชจ๋ธ์„ ๋ถ„๋ฆฌํ•˜๊ธฐ ์ „์— ํ•œ ๋ฒˆ ๊ณ ๋ฏผํ•ด ๋ณด๋ฉด ์ข‹์€ ๋ฆฌ์ŠคํŠธ๋“ค์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์œ„ ์งˆ๋ฌธ๋“ค์„ ํ†ตํ•ด ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์™€ ์˜์†์„ฑ ์—”ํ‹ฐํ‹ฐ๋กœ ๋‚˜๋ˆ„๋Š” ๊ฒƒ์„ ๊ฒฐ์‹ฌํ•˜๋”๋ผ๋„ ์‹ค์ œ ์ž‘์—…์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๋ฅผ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค.

1. ์ปจ๋ฒ„ํŒ…์„ ์œ„ํ•œ ๋ณด์ผ๋Ÿฌ ํ”Œ๋ ˆ์ดํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

์ˆœ์ˆ˜ ๋„๋ฉ”์ธ ๊ฐ์ฒด์™€ ์˜์†์„ฑ ๊ฐ์ฒด๋Š” ๋ถ„๋ฆฌ๋˜์–ด์•ผ ํ•œ๋‹ค. ์ฆ‰, ์„œ๋น„์Šค์™€ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ฐ„์˜ ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ๋ฐ˜ํ™˜ ๊ฐ’์€ ์™ธ๋ถ€์— ์˜์กดํ•˜์ง€ ์•Š๋„๋ก ์ปจ๋ฒ„ํŒ… ์ž‘์—…์ด ํ•„์š”ํ•˜๋‹ค. ๋งŒ์•ฝ ํ•˜๋‚˜์˜ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์— ๋งค์šฐ ๋งŽ์€ ์ค‘์ฒฉ ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

์ผ๋ฐ˜์ ์œผ๋กœ DDD์—์„œ๋Š” ํ•˜๋‚˜์˜ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ(๊ฐ™์€ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ๊ฐ€์ง€๋Š” ๊ด€๋ จ๋œ ๊ฐ์ฒด๋“ค์„ ๋ชจ์•„ ํ•˜๋‚˜์˜ ๋‹จ์œ„๋กœ ์ทจ๊ธ‰ํ•˜๋Š” ๊ฐœ๋…)๋ฅผ repository์˜ ๋Œ€์ƒ ์—”ํ‹ฐํ‹ฐ๋กœ ์‚ผ๋Š”๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Order๋ผ๋Š” ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๊ฐ€ ์กด์žฌํ•  ๋•Œ, ํ•ด๋‹น ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋กœ๋“œํ•˜๋Š” OrderRepository๋งŒ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค. ๊ฒฐ๊ตญ, ํ•ด๋‹น ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์— ํฌํ•จ๋˜๋Š” ๋ชจ๋“  ์—”ํ‹ฐํ‹ฐ์™€ ๋ฐธ๋ฅ˜ ๊ฐ์ฒด๋“ค์— ๋Œ€ํ•ด ํŠธ๋žœ์žญ์…˜ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•ด์•ผ ํ•˜๋ฉฐ, ์ปจ๋ฒ„ํŒ… ์ž‘์—…์— ๋งŽ์€ ์‹œ๊ฐ„์„ ์†Œ๋ชจํ•˜๊ฒŒ ๋œ๋‹ค.

๋˜ํ•œ ์ฝ”๋“œ์˜ ์–‘์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ๋งคํ•‘ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„, ๋‘ ๋ชจ๋ธ ๊ฐ„ ๋งคํ•‘์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ๋Š” ์ƒ๋‹นํ•œ ์‹œ๊ฐ„์ด ์†Œ์š”๋œ๋‹ค. ํŠนํžˆ ๋งคํ•‘ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๋‚ด๋ถ€ ๋™์ž‘ ๋ฐฉ์‹์„ ์ œ๋„ค๋ฆญ ์ฝ”๋“œ์™€ ๋ฆฌํ”Œ๋ ‰์…˜ ๋’ค๋กœ ์ˆจ๊ธธ ๊ฒฝ์šฐ, ๋งคํ•‘ ๋กœ์ง์„ ๋””๋ฒ„๊น…ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์–ด๋ ต๊ณ  ๋ณต์žกํ•˜๋‹ค.

์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ์ธํ•ด, ๋„๋ฉ”์ธ ๋ชจ๋ธ๊ณผ ์˜์†์„ฑ ๋ชจ๋ธ์˜ ๋ถ„๋ฆฌ๋Š” ๋งŽ์€ ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ , ๊ฐœ๋ฐœ์ž๋“ค์ด ์ปจ๋ฒ„ํŒ… ๋กœ์ง์— ๋งŽ์€ ์‹œ๊ฐ„์„ ํ• ์• ํ•˜๊ฒŒ ๋œ๋‹ค. ์ด๋กœ ์ธํ•ด ๊ฐœ๋ฐœ ์†๋„๊ฐ€ ์ €ํ•˜๋˜๊ณ , ๋””๋ฒ„๊น… ๊ณผ์ •์—์„œ์˜ ์–ด๋ ค์›€์ด ์ฆ๊ฐ€ํ•˜์—ฌ ์ „์ฒด์ ์ธ ์ƒ์‚ฐ์„ฑ์— ๋ถ€์ •์ ์ธ ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ๋‹ค.

2. ํœด๋จผ ์—๋Ÿฌ

์ปจ๋ฒ„ํŒ… ๋ฌธ์ œ์™€ ์ง๊ฒฐ๋œ ๋ฌธ์ œ๋กœ, ์‹ค์ˆ˜๋กœ ์ธํ•ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

public class Customer {
    private Long id;
    private String name;
    private String email;
    private String phoneNumber;  // New field added
    private Address address;

    public Customer(Long id, String name, String email, String phoneNumber, Address address) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.phoneNumber = phoneNumber;  // Initialization of new field
        this.address = address;
    }

    // Other methods..
}
@Entity
public class CustomerEntity {
    @Id
    private Long id;
    private String name;
    private String email;
    // Missing phoneNumber field
    private Address address;

    public CustomerEntity(Long id, String name, String email, Address address) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.address = address;
    }

    // Other methods..
}

์œ„ ์ฝ”๋“œ์—์„œ Customer ๊ฐ์ฒด์—๋Š” phoneNumber ํ•„๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์ง€๋งŒ, ์‹ค์ˆ˜๋กœ CustomerEntity์—๋Š” ์ถ”๊ฐ€๋˜์ง€ ์•Š์•˜๋‹ค(๋ฐ˜๋Œ€์˜ ๊ฒฝ์šฐ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค). ์ด๋Š” ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ํ™•์ธํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์•ˆ์ •์„ฑ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค. ๋ฌผ๋ก  ์ฒ ์ €ํ•˜๊ฒŒ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋ณ€ํ™˜ ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์˜ค๋ฅ˜๋ฅผ ์‚ฌ์ „์— ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ํ•ญ์ƒ ์™„๋ฒฝํ•˜์ง€๋Š” ์•Š๋‹ค.

์ด๋Ÿฌํ•œ ์‹ค์ˆ˜๋Š” ๋ณ„๋กœ ์ผ์–ด๋‚˜์ง€ ์•Š์„ ๊ฒƒ ๊ฐ™์ง€๋งŒ, ์ƒ๊ฐ๋ณด๋‹ค ๊ฐœ๋ฐœํ•˜๋Š” ๋™์•ˆ ๊ฝค๋‚˜ ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š”๋ฐ ์ƒˆ๋กœ์šด ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋„์ค‘ ๋ง์„ ๊ฑธ๊ฑฐ๋‚˜ ์ปคํ”ผํƒ€์ž„์œผ๋กœ ์ธํ•ด ์ž ๊น ์ฃผ์˜๋ฅผ ๋Œ๋ฆฐ ํ›„ ๋‹ค์‹œ ์ž‘์—…์„ ์žฌ๊ฐœํ•  ๋•Œ, ํ•„๋“œ ์ถ”๊ฐ€๋ฅผ ๊นŒ๋จน๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ž์ฃผ ์žˆ๋‹ค.

3. ๊ตฌํ˜„ ๊ธฐ์ˆ ์˜ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ ์‚ฌ์šฉ ๋ถˆ๊ฐ€

์ปจ๋ฒ„ํŒ…์˜ ์—ฐ์žฅ์„ ์œผ๋กœ, Lazy Loading์ด๋‚˜ Dirty Checking ๊ฐ™์€ JPA์—์„œ ์ง€์›ํ•˜๋Š” ๊ธฐ๋Šฅ์€ ์˜์†์„ฑ ๊ณ„์ธต์— ์˜์กดํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. ๋”ฐ๋ผ์„œ ์ปจ๋ฒ„ํŒ… ์ดํ›„์—๋Š” ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค. ์ด๋Š” ์„ฑ๋Šฅ ์ตœ์ ํ™” ๋ฐ ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ ์ธก๋ฉด์—์„œ ๋ถˆ๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋งŒ ์ด ๋ถ€๋ถ„์€ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์— ๋Œ€ํ•ด Lazy Loading์ด ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค๊ณ  ๋ณด๋Š” ์˜๊ฒฌ๋„ ๋งŽ๋‹ค. ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์— ํ•„์š”ํ•œ ๊ฐ’์€ ํ•œ ๋ฒˆ์— ๋กœ๋“œ๋˜์–ด์•ผ ํ•˜๊ณ , ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉด ๋กœ๋“œ๋˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค. Lazy Loading์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์€ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์˜ ์„ค๊ณ„๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์„ ๊ฐ€๋Šฅ์„ฑ์„ ์˜๋ฏธํ•œ๋‹ค.

๊ทธ๋Ÿฌ๋‹ˆ ์‹ ์ค‘ํžˆ ๊ณ ๋ คํ•œ ๋’ค ๋ถ„๋ฆฌํ•˜์ž

๊ฒฐ๋ก ์ ์œผ๋กœ, ๋„๋ฉ”์ธ ๋ชจ๋ธ๊ณผ ์˜์†์„ฑ ๋ชจ๋ธ์˜ ๋ถ„๋ฆฌ๋Š” ์‹ ์ค‘ํ•˜๊ฒŒ ๊ฒฐ์ •ํ•ด์•ผ ํ•˜๋ฉฐ, ํ”„๋กœ์ ํŠธ์˜ ํŠน์„ฑ, ํŒ€์˜ ์—ญ๋Ÿ‰, ์žฅ๊ธฐ์ ์ธ ์œ ์ง€๋ณด์ˆ˜์™€ ํ™•์žฅ์„ฑ์„ ๊ณ ๋ คํ•œ ์ „๋žต์ ์ธ ์ ‘๊ทผ์ด ํ•„์š”ํ•˜๋‹ค. ์ด๋Ÿฌํ•œ ๋ถ„๋ฆฌ๊ฐ€ ํ•ญ์ƒ ์ตœ์„ ์˜ ์„ ํƒ์€ ์•„๋‹ˆ๋ฉฐ, ์‹ค์ œ ํ”„๋กœ์ ํŠธ ์ƒํ™ฉ์— ๋งž๋Š” ์ตœ์ ์˜ ๊ฒฐ์ •์„ ๋‚ด๋ฆฌ๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

์‹ค์ œ๋กœ '๋งŒ๋“ค๋ฉด์„œ ๋ฐฐ์šฐ๋Š” ํด๋ฆฐ ์•„ํ‚คํ…์ฒ˜' ์ฑ…์—์„œ๋„ 8์žฅ์—์„œ ์ด ๋‘˜์˜ ๋„๋ฉ”์ธ์„ ๋‚˜๋ˆ„์ง€ ์•Š๋Š” '๋งคํ•‘ํ•˜์ง€ ์•Š๊ธฐ' ์ „๋žต์— ๋Œ€ํ•ด ๋‹ค๋ฃจ๊ณ  ์žˆ๋Š”๋ฐ, ์ด๋ฅผ ํ†ตํ•ด ๋„๋ฉ”์ธ๊ณผ ์˜์†์„ฑ ๋ชจ๋ธ์„ ๋ฐ˜๋“œ์‹œ ๋ถ„๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด ์ •๋‹ต์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

 

๊ทธ๋Ÿผ์—๋„ ์–ธ์ œ ๋ถ„๋ฆฌํ•˜๋ฉด ์ข‹์„๊นŒ?

๊ทธ๋ ‡๋‹ค๋ฉด ์–ธ์ œ ORM @Entity์™€ ๋„๋ฉ”์ธ ๋ชจ๋ธ์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„๊นŒ? ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒƒ์€ [persistence layer → domain layer] ๋ฐฉํ–ฅ์œผ๋กœ ๋ณ€๊ฒฝ ์••๋ ฅ์ด ๊ฐ€ํ•ด์ ธ์„œ๋Š” ์•ˆ ๋œ๋‹ค๋Š” ์ ์ด๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ๋ถ„๋ฆฌ๋ฅผ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ์ƒํ™ฉ์ด ์žˆ๋‹ค.

๋น„ํšจ์œจ์ ์ด๊ณ  ์ž˜๋ชป ์„ค๊ณ„๋œ ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ์˜ ๊ฒฝ์šฐ

์ž˜๋ชป ์„ค๊ณ„๋œ ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋„๋ฉ”์ธ ๊ณ„์ธต์— ๋…ธ์ถœ๋˜๋ฉด ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. ORM @Entity๋ฅผ ๋„๋ฉ”์ธ ๋ชจ๋ธ๋กœ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ์ด๋Ÿฌํ•œ ์ž˜๋ชป๋œ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋„๋ฉ”์ธ ๋ชจ๋ธ์— ๋ฐ˜์˜๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ์ด๋‹ค.

// ์ž˜๋ชป ์„ค๊ณ„๋œ ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ
@Entity
public class UserEntity {
    @Id
    private Long id;
    private String fullName; // fullName ๋Œ€์‹  firstName๊ณผ lastName์„ ๋ถ„๋ฆฌํ–ˆ์–ด์•ผ ํ•จ
    private String address1; // Address๊ฐ€ ํ•˜๋‚˜์˜ ํ•„๋“œ๋กœ ์ €์žฅ๋จ
    private String address2;
    private String address3;
}
// ๋„๋ฉ”์ธ ๋ชจ๋ธ
public class User {
    private Long id;
    private String firstName;
    private String lastName;
    private Address address; // Address ๊ฐ์ฒด๋กœ ๋ถ„๋ฆฌ
}

public class Address {
    private String street;
    private String city;
    private String state;
    private String zipCode;
}

ORM @Entity์™€ ๋„๋ฉ”์ธ ๋ชจ๋ธ์„ ๋ถ„๋ฆฌํ•˜์—ฌ, ์ž˜๋ชป ์„ค๊ณ„๋œ ํ…Œ์ด๋ธ”์˜ ์Šคํ‚ค๋งˆ๊ฐ€ ๋„๋ฉ”์ธ ๋ชจ๋ธ์— ๋ฐ˜์˜๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋„๋ฉ”์ธ ๋ชจ๋ธ์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„์˜ ๋ฌธ์ œ์ ์„ ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค.

๊ฐฑ์‹  ์ด์ƒ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์ปฌ๋Ÿผ์ด ๋ˆ„๋ฝ๋œ ๊ฒฝ์šฐ

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„ ์‹œ ๊ฐฑ์‹  ์ด์ƒ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์ค‘๋ณต์„ ์ตœ์†Œํ™”ํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ด๋‹ค. ๋‹ค๋งŒ ์ด๋กœ ์ธํ•ด ORM @Entity์™€ ๋„๋ฉ”์ธ ๋ชจ๋ธ ๊ฐ„์˜ ๋ถˆ์ผ์น˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, @Entity๋Š” ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ๊ณผ ๋™์ผํ•œ ํ•„๋“œ๋ฅผ ๊ฐ€์ง€์ง€๋งŒ, ๋„๋ฉ”์ธ ๋ชจ๋ธ์—๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ƒ ํ•„์š”ํ•œ ์ถ”๊ฐ€ ํ•„๋“œ๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ์žˆ๋‹ค.

@Entity
public class OrderEntity {
    @Id
    private Long id;
    private BigDecimal amount;
    private Long customerId; // ๊ณ ๊ฐ ์ •๋ณด๊ฐ€ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์Œ
    // ๋‹ค๋ฅธ ํ•„์š”ํ•œ ํ•„๋“œ๋“ค...
}
public class Order {
    private Long id;
    private BigDecimal amount;
    private BigDecimal tax; // ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ƒ ํ•„์š”ํ•œ ์ถ”๊ฐ€ ํ•„๋“œ
    private Customer customer; // ๊ณ ๊ฐ ์ •๋ณด ํฌํ•จ

    public BigDecimal getTotalAmount() {
        return amount.add(tax);
    }
}

public class Customer {
    private Long id;
    private String name;
    private String email;
}

๋ฌผ๋ก  @Transient ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ด๋ธ”์—๋Š” ์—†์ง€๋งŒ ๋น„์ฆˆ๋‹ˆ์Šค์—์„œ ํ•„์š”ํ•œ ํ•„๋“œ๋ฅผ ๋„๋ฉ”์ธ ๋ชจ๋ธ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ฐฉ๋ฒ•์€ ๋„๋ฉ”์ธ ๋ชจ๋ธ์ด ์˜์†์„ฑ ๊ณ„์ธต์˜ ์„ธ๋ถ€์‚ฌํ•ญ์— ์ข…์†๋˜๊ฒŒ ํ•˜์—ฌ ํ˜ผ๋ž€์„ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ๋Š” ํ•„์š”ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—๋Š” ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ•„๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ณผ์ •์—์„œ ๋ถˆ๋ช…ํ™•ํ•œ ๋™์ž‘์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ํ˜ผ๋ž€์ด ๋„๋ฉ”์ธ ๋ชจ๋ธ์— ๋ถˆํ•„์š”ํ•œ ๋ณ€๊ฒฝ ์••๋ ฅ์œผ๋กœ ์ž‘์šฉํ•˜์ง€ ์•Š๋„๋ก, ORM @Entity์™€ ๋„๋ฉ”์ธ ๋ชจ๋ธ์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋„๋ฉ”์ธ ๋ชจ๋ธ์ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ œ๋Œ€๋กœ ๋ฐ˜์˜ํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„์™€ ๋…๋ฆฝ์ ์œผ๋กœ ์œ ์ง€๋  ์ˆ˜ ์žˆ๋‹ค.

์˜์†์„ฑ ์ „์šฉ ์• ๋„ˆํ…Œ์ด์…˜์˜ ๊ณผ๋„ํ•œ ์‚ฌ์šฉ์œผ๋กœ ์ธํ•ด ๋„๋ฉ”์ธ ๋ชจ๋ธ ์˜ค์—ผ๋  ๊ฒฝ์šฐ

๋„๋ฉ”์ธ ๋ชจ๋ธ์€ ์›์น™์ ์œผ๋กœ ์ˆœ์ˆ˜ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ORM @Entity๋ฅผ ๋ถ™์ด๋Š” ๊ฒƒ์€ ์ œํ•œ์ ์œผ๋กœ ํ—ˆ์šฉ๋œ๋‹ค. ํ•˜์ง€๋งŒ ๋‹ค์–‘ํ•œ ORM ์• ๋„ˆํ…Œ์ด์…˜์ด ๊ณผ๋„ํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜๋ฉด ๋„๋ฉ”์ธ ๋ชจ๋ธ์˜ ๋ณธ์งˆ์„ ํ•ด์น  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ๋‹ค.

@Entity
@BatchSize(size = 10)
public class ProductEntity {
    @Id
    private Long id;
    private String name;
    @Version
    private int version; // ๋ฒ„์ „ ๊ด€๋ฆฌ ํ•„๋“œ
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastUpdated; // ๋งˆ์ง€๋ง‰ ์—…๋ฐ์ดํŠธ ์‹œ๊ฐ„
}
public class Product {
    private Long id;
    private String name;
    private LocalDateTime lastUpdated; // ๋„๋ฉ”์ธ ๋ชจ๋ธ์—์„œ๋Š” LocalDateTime ์‚ฌ์šฉ
}

์• ๋„ˆํ…Œ์ด์…˜์ด ๊ณผ๋„ํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ, ORM @Entity์™€ ๋„๋ฉ”์ธ ๋ชจ๋ธ์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ๋„๋ฉ”์ธ ๋ชจ๋ธ์˜ ์ˆœ์ˆ˜์„ฑ์„ ์œ ์ง€ํ•˜๊ณ , ํŠน์ • ์˜์†์„ฑ ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ๊ธฐ์ˆ ์— ์ข…์†๋˜์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค.

์ด๋Ÿฌํ•œ ์‹ ํ˜ธ๋“ค์ด ๋ณด์ธ๋‹ค๋ฉด, ๋„๋ฉ”์ธ ๋ชจ๋ธ๊ณผ ORM @Entity๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ์„ค๊ณ„์˜ ์ˆœ์ˆ˜์„ฑ์„ ์œ ์ง€ํ•˜๊ณ , ๋„๋ฉ”์ธ ๊ณ„์ธต์ด ํŠน์ • ์˜์†์„ฑ ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ๊ธฐ์ˆ ์— ์ข…์†๋˜์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‹œ์Šคํ…œ์˜ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ํ™•์žฅ์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„์™€ ๋…๋ฆฝ์ ์œผ๋กœ ๊ด€๋ฆฌ๋  ์ˆ˜ ์žˆ๋‹ค.

 

 

์ •๋ฆฌ

๊ฒฐ๊ตญ, ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ์ด์œ ๋Š” ๋„๋ฉ”์ธ ์ค‘์‹ฌ ์„ค๊ณ„๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค. ์ „ํ†ต์ ์ธ ๊ณ„์ธตํ˜• ์•„ํ‚คํ…์ฒ˜์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ํ† ๋Œ€๊ฐ€ ๋œ๋‹ค. ์›น ๊ณ„์ธต์€ ๋„๋ฉ”์ธ ๊ณ„์ธต์— ์˜์กดํ•˜๊ณ , ๋„๋ฉ”์ธ ๊ณ„์ธต์€ ์˜์†์„ฑ ๊ณ„์ธต์— ์˜์กดํ•˜๋ฏ€๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์˜์กดํ•˜๊ฒŒ ๋œ๋‹ค. ์ด๋กœ ์ธํ•ด ๋ชจ๋“  ๊ฒƒ์ด ์˜์†์„ฑ ๊ณ„์ธต์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค์–ด์ง„๋‹ค.

์šฐ๋ฆฌ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋Œ€๋ถ€๋ถ„์˜ ๋ชฉ์ ์ด ๋ฌด์—‡์ธ์ง€ ์ƒ๊ฐํ•ด ๋ณด์ž. ์šฐ๋ฆฌ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค๋ฅผ ๊ด€์žฅํ•˜๋Š” ๊ทœ์น™์ด๋‚˜ ์ •์ฑ…์„ ๋ฐ˜์˜ํ•œ ๋ชจ๋ธ์„ ๋งŒ๋“ค์–ด, ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค. ์ด๋•Œ ์šฐ๋ฆฌ๋Š” ์ƒํƒœ(state)๊ฐ€ ์•„๋‹ˆ๋ผ ํ–‰๋™(behavior)์„ ์ค‘์‹ฌ์œผ๋กœ ๋ชจ๋ธ๋งํ•œ๋‹ค. ์–ด๋–ค ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋“  ์ƒํƒœ๊ฐ€ ์ค‘์š”ํ•œ ์š”์†Œ์ด๊ธด ํ•˜์ง€๋งŒ, ํ–‰๋™์ด ์ƒํƒœ๋ฅผ ๋ณ€ํ™”์‹œํ‚ค๋Š” ์ฃผ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ํ–‰๋™์ด ๋น„์ฆˆ๋‹ˆ์Šค๋ฅผ ์ด๋Œ์–ด๊ฐ„๋‹ค.

๋”ฐ๋ผ์„œ ๋„๋ฉ”์ธ ๋ชจ๋ธ์€ ์ด๋Ÿฌํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ํ–‰๋™์„ ์ค‘์‹ฌ์œผ๋กœ ์„ค๊ณ„๋˜๋ฉด ์ข‹๋‹ค. ์˜์†์„ฑ ๊ณ„์ธต์˜ ์ œ์•ฝ์ด๋‚˜ ์„ธ๋ถ€์‚ฌํ•ญ์— ์˜ํ•ด ๋„๋ฉ”์ธ ๋ชจ๋ธ์ด ์™œ๊ณก๋˜์ง€ ์•Š๋„๋ก ORM @Entity์™€ ๋„๋ฉ”์ธ ๋ชจ๋ธ์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค. ์ด๋ ‡๊ฒŒ ํ•จ์œผ๋กœ์จ, ๋„๋ฉ”์ธ ๋ชจ๋ธ์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ œ๋Œ€๋กœ ๋ฐ˜์˜ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„์™€ ๋…๋ฆฝ์ ์œผ๋กœ ์œ ์ง€๋  ์ˆ˜ ์žˆ๋‹ค. 

 

 

+ ๋ง๋ถ™์ž„..

๋‹ค๋งŒ, ํ˜„์—…์—์„œ ๊ณ„์ธตํ˜• ์•„ํ‚คํ…์ฒ˜์™€ ํด๋ฆฐ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋ชจ๋‘ ์ ‘ํ•ด๋ณธ ์ž…์žฅ์—์„œ ๋‚˜๋Š” ์š”์ฆ˜ ์˜ค๋ฒ„์—”์ง€๋‹ˆ์–ด๋ง์— ๋Œ€ํ•ด ๋งค์šฐ ๊ฒฝ๊ณ„ํ•˜๊ณ  ์žˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์—๋Š” ์ •๋‹ต์ด ์—†์ง€๋งŒ, ํด๋ฆฐ ์•„ํ‚คํ…์ฒ˜๋‚˜ ํ—ฅ์‚ฌ๊ณ ๋‚  ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•ด์„œ ์ž˜ํ•˜๋Š” ๊ฐœ๋ฐœ์ž์ด๊ณ , ๊ณ„์ธตํ˜• ์•„ํ‚คํ…์ฒ˜๋กœ ๊ฐœ๋ฐœํ•œ๋‹ค๊ณ  ํ•ด์„œ ๋ชปํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋Š” ์•„๋‹ˆ๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค. ๊ตฌํ˜„์ฒด๊ฐ€ ํ•˜๋‚˜๋ฟ์ธ๋ฐ๋„ ์•ž๋‹จ์— ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋‘์ง€ ์•Š์•˜์œผ๋‹ˆ DIP๋ฅผ ์–ด๊ฒผ๊ธฐ์— ๋‚˜์œ ์ฝ”๋“œ์ธ๊ฐ€? ํ›„์— ๋ฆฌํŒฉํ„ฐ๋ง์„ ํ•˜๋ฉด ์•ˆ ๋˜๋Š” ๊ฑธ๊นŒ? ๋‹น์žฅ 3๋…„ ์•ˆ์— ์ €์žฅ์†Œ๊ฐ€ ๋ณ€๊ฒฝ๋  ์ผ์ด ์—†๊ณ  ํŠธ๋ž˜ํ”ฝ๋„ ์ ์€ ์„œ๋น„์Šค์—์„œ MSA๋‚˜ CQRS๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ •๋ง ํ•„์š”ํ•œ ๊ฑธ๊นŒ? ํŒ€์›๋“ค์˜ ํ•™์Šต ๊ณก์„ ์„ ๊ณ ๋ คํ•˜์ง€ ์•Š์•„ ํŒ€์˜ ๊ฐœ๋ฐœ ์†๋„๊ฐ€ ๋Šฆ์ถฐ์ง€๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ์€ ์ผ์ผ๊นŒ? RDD(์ด๋ ฅ์„œ ์ฃผ๋„ ๊ฐœ๋ฐœ)์ด ๋˜๋ฉด ์•ˆ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

์šฐ๋ฆฌ๋Š” ๊ฐœ๋ฐœ์ž์ด๊ธฐ ์ด์ „์— ํ•œ ํšŒ์‚ฌ์—์„œ ๋ˆ์„ ๋ฐ›๋Š” ์ง์›์ด๊ณ , ์ œํ’ˆ์„ ๋น ๋ฅด๊ณ  ๊ฒฝ์Ÿ๋ ฅ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด ๊ณ ๊ฐ์˜ ๋งŒ์กฑ์„ ๋†’์ด๋Š” ์ผ์„ ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— ์ค‘์š”ํ•œ ๊ฒƒ์€ ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑ์‹œํ‚ค๊ณ  ํŒ€์˜ ์ƒ์‚ฐ์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์ ์ ˆํ•œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด๋‹ค. '์€์ด์•Œ์€ ์—†๋‹ค(No Silver Bullet)'๋ผ๋Š” ๋ง์ด ์žˆ๋“ฏ์ด ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋งŒ๋Šฅ์˜ ์•„ํ‚คํ…์ฒ˜๋‚˜ ์„ค๊ณ„๋Š” ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

 

์ฐธ๊ณ