Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
1ce635f
chore: DB Connection ์„ค์ • ๋ณ€๊ฒฝ โ€“ HikariCP, Hibernate Auto-Commit ๋น„ํ™œ์„ฑํ™”๋กœ Dbโ€ฆ
nomoreFt Feb 25, 2025
7f3a747
chore: docker compose ์ถ”๊ฐ€
nomoreFt Feb 25, 2025
28bb200
feat(core): ๊ธฐ๋ณธ Entity Type ์ถ”๊ฐ€
nomoreFt Feb 25, 2025
6626e1a
feat(core): ๊ณตํ†ต Money ํƒ€์ž…, Converter ์ถ”๊ฐ€
nomoreFt Feb 25, 2025
54e1cce
refactor(product): Product ๋ฆฌํŒฉํ† ๋ง
nomoreFt Feb 25, 2025
ef2b0b9
refactor(product): Product ๋ฆฌํŒฉํ† ๋ง
nomoreFt Feb 25, 2025
4696cff
chore: ์ค‘๋ณต docker compose ์‚ญ์ œ
nomoreFt Feb 27, 2025
5bd913b
refactor: Product refactoring
nomoreFt Feb 27, 2025
956a3f4
refactor(product): Service ๊ฐœ์„  ์ง„ํ–‰
nomoreFt Feb 28, 2025
4061ecb
refactor(product): ๊ธฐ์กด ๋„๋ฉ”์ธ ๋ฆฌํŒฉํ† ๋ง + ๊ด€๋ จ๋œ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ์ˆ˜์ • ๋ฐ ํ…Œ์ŠคํŠธ ์ •์ƒ ์ž‘๋™
nomoreFt Mar 1, 2025
893b1e9
refactor(product): ๊ธฐ์กด ๋„๋ฉ”์ธ ๋ฆฌํŒฉํ† ๋ง + ๊ด€๋ จ๋œ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ์ˆ˜์ • ๋ฐ ํ…Œ์ŠคํŠธ ์ •์ƒ ์ž‘๋™
nomoreFt Mar 3, 2025
a8f25d6
chore(product): flyway ์„ค์ •
nomoreFt Mar 3, 2025
5d63264
feat(product): ๊ณตํ†ต AggregateRoot ํƒ€์ž… ์„ ์–ธ
nomoreFt Mar 3, 2025
cae28ff
refactor(product): ValueObject ์ž์ž˜ํ•œ ์ˆ˜์ •
nomoreFt Mar 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: '3.8'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docker-compose ํŒŒ์ผ์ด docker ๋””๋ ‰ํ† ๋ฆฌ์— ์ด๋ฏธ ์žˆ๋Š”๊ฑธ๋กœ ์•Œ๊ณ ์žˆ๋Š”๋ฐ, docker-compose file์„ ๋ฐ–์— ๋”ฐ๋กœ ๋‘์‹  ์ด์œ ๊ฐ€ ์žˆ์œผ์‹ ๊ฐ€์š”? ๐Ÿ‘€

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

์•„ ์žˆ๋Š”์ค„ ๋ชฐ๋ž๋„ค์š” ใ…Žใ…Ž ์‚ญ์ œํ–ˆ์Šต๋‹ˆ๋‹ค.


services:
mysql:
image: mysql:8.0
container_name: kitchenpos-mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: kitchenpos
MYSQL_USER: user
MYSQL_PASSWORD: password
ports:
- "33306:3306"
command: --default-authentication-plugin=mysql_native_password
volumes:
- mysql_data:/var/lib/mysql

volumes:
mysql_data:
10 changes: 5 additions & 5 deletions src/main/java/kitchenpos/menus/application/MenuService.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import kitchenpos.menus.domain.MenuRepository;
import kitchenpos.products.domain.Product;
import kitchenpos.products.domain.ProductRepository;
import kitchenpos.products.infra.PurgomalumClient;
import kitchenpos.shared.domain.ProfanityChecker;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -23,18 +23,18 @@ public class MenuService {
private final MenuRepository menuRepository;
private final MenuGroupRepository menuGroupRepository;
private final ProductRepository productRepository;
private final PurgomalumClient purgomalumClient;
private final ProfanityChecker profanityChecker;

public MenuService(
final MenuRepository menuRepository,
final MenuGroupRepository menuGroupRepository,
final ProductRepository productRepository,
final PurgomalumClient purgomalumClient
final ProfanityChecker profanityChecker
) {
this.menuRepository = menuRepository;
this.menuGroupRepository = menuGroupRepository;
this.productRepository = productRepository;
this.purgomalumClient = purgomalumClient;
this.profanityChecker = profanityChecker;
}

@Transactional
Expand Down Expand Up @@ -79,7 +79,7 @@ public Menu create(final Menu request) {
throw new IllegalArgumentException();
}
final String name = request.getName();
if (Objects.isNull(name) || purgomalumClient.containsProfanity(name)) {
if (Objects.isNull(name) || profanityChecker.containsProfanity(name)) {
throw new IllegalArgumentException();
}
final Menu menu = new Menu();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import kitchenpos.menus.domain.MenuRepository;
import kitchenpos.products.domain.Product;
import kitchenpos.products.domain.ProductRepository;
import kitchenpos.products.infra.PurgomalumClient;
import kitchenpos.shared.domain.ProfanityChecker;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -19,16 +19,16 @@
public class ProductService {
private final ProductRepository productRepository;
private final MenuRepository menuRepository;
private final PurgomalumClient purgomalumClient;
private final ProfanityChecker profanityChecker;

public ProductService(
final ProductRepository productRepository,
final MenuRepository menuRepository,
final PurgomalumClient purgomalumClient
final ProfanityChecker profanityChecker
) {
this.productRepository = productRepository;
this.menuRepository = menuRepository;
this.purgomalumClient = purgomalumClient;
this.profanityChecker = profanityChecker;
}

@Transactional
Expand All @@ -38,7 +38,7 @@ public Product create(final Product request) {
throw new IllegalArgumentException();
}
final String name = request.getName();
if (Objects.isNull(name) || purgomalumClient.containsProfanity(name)) {
if (Objects.isNull(name) || profanityChecker.containsProfanity(name)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProductName.create ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด์„œ ProductName์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ณ ,
ํ•ด๋‹น ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ์—์„œ ์ƒ์„ฑํ•  ๋•Œ, ํ•„์š”ํ•œ ์œ ํšจ์„ฑ ๊ฒ€์ฆ๋“ค์„ ๋ชจ๋‘ ํ•ด์ฃผ๊ณ ์žˆ๋Š”๋ฐ์š”.

๊ตฌํ˜„ํ•ด์ฃผ์‹  create ๋ฉ”์„œ๋“œ๋กœ ProductName ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋„๋ก ๋ณ€๊ฒฝํ•ด๋ณด๋ฉด ์–ด๋–จ๊นŒ์š”? ๐Ÿ˜ƒ

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProductNamePolicy๋กœ ์•„์˜ˆ ๋ถ„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

product context์—์„œ ์ œ๊ณตํ•˜๋Š” API๋“ค์— ๋Œ€ํ•ด์„œ ์š”์ฒญ ํ˜น์€ ์‘๋‹ต ๊ฐ’์œผ๋กœ DomainEntity๋ฅผ ๊ทธ๋Œ€๋กœ ์“ฐ๊ณ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ, DTO๋กœ ๋ณ€๊ฒฝํ•ด๋ณด๋ฉด ์–ด๋–จ๊นŒ์š”? ๐Ÿ‘€

throw new IllegalArgumentException();
}
final Product product = new Product();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๋˜ํ•œ Product ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์ง€๊ธˆ์ฒ˜๋Ÿผ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ ๋’ค, setter๋ฅผ ํ†ตํ•ด ์ƒํƒœ ๊ฐ’์„ ์ดˆ๊ธฐํ™”ํ•ด์ฃผ๋Š” ๋ฐฉ์‹ ๋Œ€์‹ ์—,
์ƒ์„ฑ์ž ํ˜น์€ ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด์„œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋„๋ก ๋ณ€๊ฒฝํ•ด์ฃผ์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์š”. ๐Ÿ˜‰

Expand Down
5 changes: 0 additions & 5 deletions src/main/java/kitchenpos/products/infra/PurgomalumClient.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kitchenpos.products.infra;

import kitchenpos.products.tobe.domain.Product;
import kitchenpos.products.tobe.domain.ProductId;
import kitchenpos.products.tobe.domain.TobeProductRepository;
import org.springframework.data.jpa.repository.JpaRepository;

public interface TobeJpaProductRepository extends TobeProductRepository, JpaRepository<Product, ProductId> {
}
52 changes: 52 additions & 0 deletions src/main/java/kitchenpos/products/tobe/domain/Product.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package kitchenpos.products.tobe.domain;

import jakarta.persistence.*;
import kitchenpos.shared.domain.DomainEntity;
import kitchenpos.shared.domain.Money;

import java.math.BigDecimal;
import java.util.Objects;
import java.util.UUID;

@Table(name = "product_tobe")
@Entity(name = "ProductTobe")
public class Product extends DomainEntity<Product, ProductId> {

@EmbeddedId
@AttributeOverride(name = "value", column = @Column(name = "id"))
private ProductId id;

@Embedded
@AttributeOverride(name = "name", column = @Column(name = "name", nullable = false))
private ProductName name;

@Embedded
@AttributeOverride(name = "price", column = @Column(name = "price", nullable = false))
private ProductPrice price;

@SuppressWarnings("unused")
protected Product() {}

private Product(ProductId id, ProductName name, ProductPrice price) {
this.id = Objects.requireNonNull(id, "id must not be null");
this.name = Objects.requireNonNull(name, "name must not be null");
this.price = Objects.requireNonNull(price, "price must not be null");
}

public static Product create(ProductId id, ProductName name, ProductPrice price) {
return new Product(id, name, price);
}

/**
* getter
*/
@Override
public ProductId getId() {
return id;
}

public ProductName getName() { return name; }

public ProductPrice getPrice() { return price; }

}
30 changes: 30 additions & 0 deletions src/main/java/kitchenpos/products/tobe/domain/ProductId.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package kitchenpos.products.tobe.domain;

import jakarta.persistence.Embeddable;
import kitchenpos.products.tobe.domain.exception.InvalidProductIdException;

import java.io.Serializable;

@Embeddable
public class ProductId implements Serializable {

private String value;

@SuppressWarnings("unused")
protected ProductId() {}

private ProductId(String value) {
if (value == null || value.isBlank()) {
throw new InvalidProductIdException("Product ID ๋Š” null ์ด๊ฑฐ๋‚˜ ๋นˆ ๊ฐ’์ด ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}
this.value = value.strip();
}

public static ProductId of(String value) {
return new ProductId(value);
}

public String getValue() {
return value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package kitchenpos.products.tobe.domain;

public interface ProductIdGenerator {
ProductId generateId();
}
42 changes: 42 additions & 0 deletions src/main/java/kitchenpos/products/tobe/domain/ProductName.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package kitchenpos.products.tobe.domain;

import jakarta.persistence.Embeddable;
import jakarta.persistence.Transient;
import kitchenpos.products.tobe.domain.exception.InvalidProductNameException;
import kitchenpos.shared.domain.ProfanityChecker;
import kitchenpos.shared.domain.ValueObject;

@Embeddable
public class ProductName extends ValueObject<ProductName> {

private String name;

@SuppressWarnings("unused")
protected ProductName() {}

// ์™ธ๋ถ€์—์„œ ์ง์ ‘ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋Š” private ์ƒ์„ฑ์ž: ๊ฒ€์ฆ๋œ ์ด๋ฆ„๋งŒ ๋ฐ›์Œ
private ProductName(String name) {
this.name = name;
}

public static ProductName create(ProfanityChecker profanityChecker, String name) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(์งˆ๋ฌธ) ProductName์ด ๋น„์†์–ด ๊ฒ€์ฆ์ด ๊ผญ ํ•„์š”ํ•˜๋‹ค๋Š” ์ ์„ ๋‚ด๋ถ€ ์ƒ์„ฑํ•  ๋•Œ ํ‘œํ˜„ํ•˜๊ณ  ์‹ถ์€๋ฐ, ProfanityChecker๋ฅผ static factory ์ƒ์„ฑ์ž์—์„œ ์˜์กดํ•˜๋Š”๊ฒŒ ๋งž์„์ง€ ๊ณ ๋ฏผ์ด ๋˜๋„ค์š”.

ProductName ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ์žˆ์–ด ProfanityChecker์ด ์ง์ ‘์ ์œผ๋กœ ๊ด€์—ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด ์•„๋‹๊นŒ ์‹ถ์–ด์š”.
ProductName ์ƒ์„ฑ ์ •์ฑ…์„ ๊ฒ€์ฆํ•ด์ฃผ๋Š” ์—ญํ• ์„ ๋„๋ฉ”์ธ ์„œ๋น„์Šค ๊ฐ์ฒด(ex. ProdcutNamePolicy)์—๊ฒŒ ์œ„์ž„ํ•ด๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์•„์š”.

if (name == null || name.isBlank()) {
throw new InvalidProductNameException("Product name ์€ null ์ด๊ฑฐ๋‚˜ ๋นˆ ๊ฐ’์ด ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}

if (profanityChecker.containsProfanity(name)) {
throw new InvalidProductNameException("Product name ์— ๋น„์†์–ด๊ฐ€ ํฌํ•จ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}
return new ProductName(name.strip());
}

public String getName() {
return name;
}

@Override
@Transient
protected Object[] getEqualityFields() {
return new Object[] { name };
}
}
30 changes: 30 additions & 0 deletions src/main/java/kitchenpos/products/tobe/domain/ProductPrice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package kitchenpos.products.tobe.domain;

import kitchenpos.products.tobe.domain.exception.InvalidProductPriceException;
import kitchenpos.shared.domain.Money;
import kitchenpos.shared.domain.ValueObject;

public class ProductPrice extends ValueObject<ProductPrice> {
private Money price;

private ProductPrice(Money price) {
if (price == null || price.isLessThan(Money.ZERO)) {
throw new InvalidProductPriceException("์ƒํ’ˆ ๊ฐ€๊ฒฉ์€ null ์ด๊ฑฐ๋‚˜ 0๋ณด๋‹ค ์ž‘์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}

this.price = price;
}

public static ProductPrice of(Money price) {
return new ProductPrice(price);
}

public Money getPrice() {
return price;
}

@Override
protected Object[] getEqualityFields() {
return new Object[] { price };
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package kitchenpos.products.tobe.domain;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

@Repository
@Transactional
public interface TobeProductRepository {
Product save(Product product);

Optional<Product> findById(ProductId id);

List<Product> findAll();

List<Product> findAllByIdIn(List<ProductId> ids);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kitchenpos.products.tobe.domain.exception;

public class InvalidProductIdException extends IllegalArgumentException {
public InvalidProductIdException(String s) {
super(s);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kitchenpos.products.tobe.domain.exception;

public class InvalidProductNameException extends IllegalArgumentException {
public InvalidProductNameException(String s) {
super(s);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kitchenpos.products.tobe.domain.exception;

public class InvalidProductPriceException extends IllegalArgumentException {
public InvalidProductPriceException(String s) {
super(s);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package kitchenpos.products.tobe.domain.support;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProductIdGenerator์˜ ๊ตฌํ˜„์ฒด์ธ UUIDBasedProductIdGenerator๋Š” support ํŒจํ‚ค์ง€์— ์œ„์น˜์‹œํ‚ค์‹  ์ด์œ ๊ฐ€ ์žˆ์œผ์‹ค๊นŒ์š”?
์˜๋„๊ฐ€ ๊ถ๊ธˆํ•ด์„œ ์งˆ๋ฌธ๋“œ๋ฆฝ๋‹ˆ๋‹ค : )

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UUID, ProductNamePolicy ์™€ ๊ฐ™์ด domain์— ์•„์ฃผ ๋ฐ€์ ‘ํ•œ ๊ตฌํ˜„์ฒด ์ž์ฒด๋Š” ๋‚ด๋ถ€์— ์œ„์น˜์‹œํ‚ค๋ ค ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ˆœ ํŒจํ‚ค์ง•์— ๋Œ€ํ•œ ๊ตฌ๋ถ„์ž…๋‹ˆ๋‹ค.


import kitchenpos.products.tobe.domain.ProductId;
import kitchenpos.products.tobe.domain.ProductIdGenerator;
import org.springframework.stereotype.Component;

import java.util.UUID;

@Component
public class UUIDBasedProductIdGenerator implements ProductIdGenerator {
@Override
public ProductId generateId() {
return ProductId.of(UUID.randomUUID().toString());
}
}
37 changes: 37 additions & 0 deletions src/main/java/kitchenpos/shared/domain/DomainEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package kitchenpos.shared.domain;

import java.io.Serializable;

public abstract class DomainEntity<T extends DomainEntity<T, TID>, TID> implements Serializable {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DomainEntity์™€ ValueObject์—์„œ ๊ณตํ†ต๋˜๋Š” ์š”์†Œ๋ฅผ ์ถ”์ƒ ํด๋ž˜์Šค๋กœ ๋ฝ‘์•„๋‚ด์…จ๊ตฐ์š”? ๐Ÿ‘๐Ÿ’ฏ

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AggregateRoot๋„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

@Override
public boolean equals(Object other) {
if (other == null) {
return false;
}

return equals((T)other);
}

public boolean equals(T other) {
if (other == null) {
return false;
}

if (getId() == null) {
return false;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

์‚ฌ์†Œํ•˜์ง€๋งŒ ์•„๋ž˜์ฒ˜๋Ÿผ ๋ณ€๊ฒฝํ•ด๋ณผ ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ ๊ฐ™๋„ค์š”.

Suggested change
if (other == null) {
return false;
}
if (getId() == null) {
return false;
}
if (other == null || getId() == null) {
return false;
}


if (other.getClass().equals(getClass())) {
return getId().equals(other.getId());
}

return super.equals(other);
}

@Override
public int hashCode() {
return getId() == null ? 0 : getId().hashCode();
}

abstract public TID getId();
}
Loading