woowacourse-teams / 2024-code-zap

์ฝ”๋“œ ํ…œํ”Œ๋ฆฟ, Zap์‹ธ๊ฒŒ ์ €์žฅํ•˜๊ณ ! Zap์‹ธ๊ฒŒ ๊ณต์œ ํ•˜์ž! ์ฝ”๋“œ์žฝ โšก
https://www.code-zap.com
27 stars 8 forks source link

[REFACTOR] Service Layer ๋ฆฌํŒฉํ† ๋ง #650

Open jminkkk opened 2 months ago

jminkkk commented 2 months ago

๐Ÿ“Œ ์–ด๋–ค ๊ธฐ๋Šฅ์„ ๋ฆฌํŒฉํ„ฐ๋ง ํ•˜๋‚˜์š”?

ํ•ด๋‹น Service Layer ํ…Œ์ŠคํŠธ ์ค‘ ๋ฐœ๊ฒฌ๋œ ๊ฐœ์„ ์ด ํ•„์š”ํ•œ ์‚ฌํ•ญ๋“ค์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค.

์ถ”๊ฐ€๋กœ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์—์„œ๋„ Service Layer ๋ฆฌํŒฉํ† ๋ง์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด ์ฝ”๋ฉ˜ํŠธ๋กœ ์ด๋ฅผ ๋‚จ๊ฒจ์ฃผ์‹œ๊ณ  ์ด์Šˆ ๋ณธ๋ฌธ์˜ TODO์— ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.

TODO

jminkkk commented 2 months ago

TemplateTagService, TagService ๋ถ„๋ฆฌ

๐Ÿ“Œ ์–ด๋–ค ๊ธฐ๋Šฅ์„ ๋ฆฌํŒฉํ„ฐ๋ง ํ•˜๋‚˜์š”?

codezap.tag.service ์•„๋ž˜์˜ TemplateTagService๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. TagService๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ Tag ๋„๋ฉ”์ธ์—๋งŒ ํ•ด๋‹นํ•˜๋Š” ๋กœ์ง๋“ค์„ TemplateTagService๊ฐ€ ์•„๋‹Œ ์ƒˆ ์„œ๋น„์Šค๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด TemplateTagService๋Š” TemplateTag์— ํ•ด๋‹นํ•˜๋Š” ๋กœ์ง๋“ค์„ ๋‘ก๋‹ˆ๋‹ค.

๋‘ ๋„๋ฉ”์ธ์— ๋Œ€ํ•œ ๋กœ์ง๋“ค์€ TemplateTagApplicationService ์— ๋‘๋Š” ๊ฒƒ์ด ๋” ์ ์ ˆํ•˜๋‹ค๊ณ  ์ƒ๊ฐ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ์‹œ๋กœ ์ƒ์„ฑ์— ๋Œ€ํ•œ ๋ถ€๋ถ„ ์˜ˆ์‹œ๋ฅผ ๋‘๊ฒ ์Šต๋‹ˆ๋‹ค.

AS-IS

// TemplateTagService.java

    @Transactional
    public void createTags(Template template, List<String> tagNames) {
        List<String> existingTags = tagRepository.findNameByNamesIn(tagNames);
        templateTagRepository.saveAll(
                existingTags.stream()
                        .map(tagRepository::fetchByName)
                        .map(tag -> new TemplateTag(template, tag))
                        .toList()
        );

        List<Tag> newTags = tagRepository.saveAll(
                tagNames.stream()
                        .filter(tagName -> !existingTags.contains(tagName))
                        .map(Tag::new)
                        .toList()
        );
        templateTagRepository.saveAll(
                newTags.stream()
                        .map(tag -> new TemplateTag(template, tag))
                        .toList()
        );
    }

TO-BE

// // TemplateTagApplicationService.java

    @Transactional
    public void createTemplateTags(Template template, List<String> tagNames) {
        List<Tag> tags = tagService.findOrCreateTags(tagNames);
        templateTagService.createTemplateTag(template, newTags);
    }
// TemplateTagService.java

    @Transactional
    public void createTemplateTags(Template template, List<Tag> tags) {
        List<TemplateTag> templateTags = tags.stream()
            .map(tag -> new TemplateTag(template, tag))
            .collect(Collectors.toList());

        templateTagRepository.saveAll(templateTags);
    }
// TagService.java

    @Transactional
    public List<Tag> findOrCreateTags(Template template, List<String> tagNames) {
        List<Tag> existingTags = tagRepository.findAllByNamesIn(tagNames);
        List<Tag> newTags = this.createTags(existingTags, newTagNames);
        return existingTags.saveAll(newTags);
    }

AS-IS

// TemplateTagService.java

    public List<Tag> getByTemplate(Template template) {
        return templateTagRepository.findAllByTemplate(template).stream()
                .map(TemplateTag::getTag)
                .toList();
    }

TO-BE

// TagService๋กœ ์ด๋™
    public List<Tag> getAllByTemplate(List<TemplateTag> templateTags) {
        return templateTags.stream()
                .map(TemplateTag::getTag)
                .toList();
    }
jminkkk commented 2 months ago

SourceCodeService์— ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ ์ œ๊ฑฐ ๋ฐ ๊ฐœ์„ 

AS-IS

  1. image
  2. @Transactional
    public void deleteByIds(List<Long> templateIds) {
        templateIds.forEach(sourceCodeRepository::deleteByTemplateId);
    }

deleteByTemplateId ๋ฉ”์„œ๋“œ n๋ฒˆ ํ˜ธ์ถœ & ์ฟผ๋ฆฌ n๋ฒˆ

  1. sourceCodeService.deleteByIds()

์†Œ์Šค ์ฝ”๋“œ ์•„์ด๋””๋กœ ์‚ญ์ œํ•˜๋Š” ๊ฒƒ ๊ฐ™์ง€๋งŒ ํ…œํ”Œ๋ฆฟ ์•„์ด๋””๋กœ ์‚ญ์ œํ•˜๋Š” ๊ฒƒ์ž„ ์œ„์™€ ๊ฐ™์€ ํ˜ผ๋™ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋ช… ๋ณ€๊ฒฝํ•˜๊ธฐ

TO-BE

1.

image
    @Transactional
    public void deleteByIds(List<Long> templateIds) {
        sourseCodeRepository.deleteAllByTemplateId(templateIds);

        // ๋˜๋Š” sourseCodeRepository.deleteAllByTemplateIdInBatch(templateIds);
    }

๊ฐ๊ฐ repository ๋ฉ”์„œ๋“œ 1๋ฒˆ ํ˜ธ์ถœ & ์ฟผ๋ฆฌ n๋ฒˆ(deleteAllByTemplateId) ๋˜๋Š” 1๋ฒˆ(deleteAllByTemplateIdInBatch)

๋“ฑ๋“ฑ์ด ๋” ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. sourceCodeService.deleteByTemplateIds()

๐Ÿ” ์ฐธ๊ณ ํ• ๋งŒํ•œ ์ž๋ฃŒ(์„ ํƒ)

createSourceCodes() ๋ฉ”์„œ๋“œ์— @Transactional ๊ด€๋ จ

createSourceCodes์—์„œ๋Š” saveAll๋งŒ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ฌถ์ด์ง€ ์•Š์•„๋„ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค~ ๋˜ํ•œ saveAll์€ ์ด๋ฏธ ๋‚ด๋ถ€์—์„œ @Transactional๋ฅผ ์„ ์–ธํ•˜๊ณ  ์žˆ์–ด ์ผ๋ถ€ save ์‹คํŒจ ์‹œ ๋กค๋ฐฑ๋ฉ๋‹ˆ๋‹ค.

image
jminkkk commented 2 months ago

SourceCodeService ์ค‘ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๋กœ์ง ์ˆ˜์ •

๊ฐ ์ผ€์ด์Šค์— ๋Œ€ํ•ด ๊ฒ€์ฆ ๋˜๋Š” ๋กœ์ง ๋ณ€๊ฒฝ์ด ํ•„์š”

์†Œ์Šค ์ฝ”๋“œ ์ƒ์„ฑ ์‹คํŒจ ์ผ€์ด์Šค

์†Œ์Šค ์ฝ”๋“œ ์ˆ˜์ • ์„ฑ๊ณต ์ผ€์ด์Šค

์†Œ์Šค ์ฝ”๋“œ ์ˆ˜์ • ์‹คํŒจ ์ผ€์ด์Šค

jminkkk commented 2 months ago

CategoryTemplateApplicationService๋ฅผ ํฌํ•จํ•œ ํŒŒ์‚ฌ๋“œ ์„œ๋น„์Šค, ํ•˜์œ„ ์„œ๋น„์Šค์˜ ์—ญํ• ๊ณผ ์ฑ…์ž„

๋‹จ์ผ ์ฑ…์ž„ ์›์น™ (SRP)

์ถ”์ƒํ™” ์ˆ˜์ค€ (DIP ๊ด€๋ จ)

ํ˜„์žฌ ๊ตฌ์กฐ์—์„œ๋Š” ์นดํ…Œ๊ณ ๋ฆฌ ๊ด€๋ จ ๋กœ์ง ๋ณ€๊ฒฝ ์‹œ ํŒŒ์‚ฌ๋“œ ํด๋ž˜์Šค๋„ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค. == ์œ ์ง€๋ณด์ˆ˜์— ์ข‹์ง€ ์•Š๋‹ค. ๊ฒ€์ƒ‰ ์กฐ๊ฑด์—์„œ ์นดํ…Œ๊ณ ๋ฆฌ ์กฐํšŒ๋„ ์ถ”๊ฐ€๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์š”๊ตฌ์‚ฌํ•ญ์ด ๋ณ€๊ฒฝ๋œ๋‹ค๋ฉด? ๋งŒ์•ฝ ํšŒ์›๋‹น ํ•œ๊ฐœ์”ฉ ์žˆ๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๋ชจ๋“  ํšŒ์›์ด ๊ฐ™์ด ์‚ฌ์šฉํ•ด์•ผ๋งŒ ํ•œ๋‹ค๋ฉด?

category.validateAuthorization(member)๋ฅผ ์ œ๊ฑฐํ•ด์•ผ ํ•˜๋ฏ€๋กœ ํŒŒ์‚ฌ๋“œ๋„ ํ•จ๊ป˜ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•œ๋‹ค. ์ฆ‰ ํŒŒ์‚ฌ๋“œ์˜ ์žฅ์ ์ธ ์„œ๋ธŒ์‹œ์Šคํ…œ ๋‚ด๋ถ€ ์„ค๊ณ„์˜ ๋ณ€๊ฒฝ์ด ๋‹ค๋ฅธ ์„œ๋ธŒ์‹œ์Šคํ…œ์— ๋…๋ฆฝ์ ์œผ๋กœ ์ž์œ ๋กญ๊ฒŒ ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๊ณผ ๋ฉ€์–ด์ง„๋‹ค.

์š”์•ฝ

์ฆ‰, CategoryTemplateApplicationService ๋Š” ์นดํ…Œ๊ณ ๋ฆฌ ์„œ๋น„์Šค์—๊ฒŒ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๊ฐ€์ ธ์˜ค๋„๋ก ์š”์ฒญ๋งŒ ํ•ด์•ผ ํ•˜๋ฉฐ, ์นดํ…Œ๊ณ ๋ฆฌ ์„œ๋น„์Šค์—์„œ ์ค˜๋„ ๋˜๋Š”์ง€(๊ถŒํ•œ ์ฒดํฌ), ์žˆ๋Š”์ง€ ์—†๋Š”์ง€(fetchBy) ๋“ฑ์„ ํŒ๋‹จํ•ด์•ผํ•จ

AS-IS

@Service
@RequiredArgsConstructor
public class CategoryTemplateApplicationService {
    private final CategoryService categoryService;
    private final TemplateApplicationService templateApplicationService;

    public Long createTemplate(Member member, CreateTemplateRequest createTemplateRequest) {
        Category category = categoryService.fetchById(createTemplateRequest.categoryId());
        category.validateAuthorization(member);
        return templateApplicationService.createTemplate(member, category, createTemplateRequest);
    }

    public void update(Member member, Long templateId, UpdateTemplateRequest updateTemplateRequest) {
        Category category = categoryService.fetchById(updateTemplateRequest.categoryId());
        category.validateAuthorization(member);
        templateApplicationService.update(member, templateId, updateTemplateRequest, category);
    }
}

TO-BE

@Service
@RequiredArgsConstructor
public class CategoryTemplateApplicationService {
    private final CategoryService categoryService;
    private final TemplateApplicationService templateApplicationService;

    public Long createTemplate(Member member, CreateTemplateRequest createTemplateRequest) {
        Category category = categoryService.findById(createTemplateRequest.categoryId(), member.getId());
        return templateApplicationService.createTemplate(member, category, createTemplateRequest);
    }

    public void update(Member member, Long templateId, UpdateTemplateRequest updateTemplateRequest) {
        Category category = categoryService.findById(updateTemplateRequest.categoryId(), member.getId());
        templateApplicationService.update(member, templateId, updateTemplateRequest, category);
    }
}
zangsu commented 2 months ago

Member.equals() ์—์„œ ํด๋ž˜์Šค ๋น„๊ต ์ œ๊ฑฐ

ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ Category ์˜ ํ•„๋“œ๋กœ ์‚ฌ์šฉ๋˜๊ณ , lazy loading ์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ ํ”„๋ก์‹œ ๊ฐ์ฒด์™€ Member ๊ฐ์ฒด์˜ ๋™๋“ฑ์„ฑ ๋น„๊ต๊ฐ€ ์ƒ๊ธด๋‹ค. ์ด ๋•Œ๋ฌธ์— ํด๋ž˜์Šค ๋น„๊ต๋ฅผ ์ œ๊ฑฐํ•ด์•ผ ํ•œ๋‹ค.

if (o == null || getClass() != o.getClass()) {
    return false;
}
zangsu commented 2 months ago

DB ์˜ˆ์™ธ ํ•ธ๋“ค๋ง์ด ํ•„์š”ํ• ์ง€ ๊ณ ๋ฏผ

CategoryService.findAllByMemer(Member member) ์— ์ €์žฅ๋˜์ง€ ์•Š์€ ๋ฉค๋ฒ„๊ฐ€ ๋“ค์–ด๊ฐ€๋ฉด DB ์˜ˆ์™ธ ๋ฐœ์ƒ

์ด ๋ถ€๋ถ„์„ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด ์ฃผ์–ด์•ผ ํ• ์ง€~

๊ด€๋ จ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

zangsu commented 2 months ago

CategoryTemplateService ์„ CategoryService ๋กœ ํ†ตํ•ฉ

ํ˜„์žฌ CategoryTemplateService ์˜ public ๋ฉ”์„œ๋“œ๋Š” deleteById() ํ•˜๋‚˜๋ฐ–์— ์—†์Œ. ๊ทธ๋ฆฌ๊ณ , ์ด ๋ฉ”์„œ๋“œ๋Š” TemplateRepository ์˜ ์˜์กด์„ฑ์ด ํ•„์š”ํ•˜๋‹ค๋Š” ์ด์œ  ์ด์™ธ์—๋Š” ํด๋ž˜์Šค๊ฐ€ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์„ ์ด์œ ๊ฐ€ ์—†์Œ.

์ด์— CategoryServiceํด๋ž˜์Šค๋กœ์˜ ํ†ตํ•ฉ์„ ์ œ์•ˆ

kyum-q commented 2 months ago

Fixture ์ •๋ฆฌ

MemberFixture ๋‘๊ฐœ

MemberFixture๊ฐ€ ๋‘ ๊ฐœ ์กด์žฌํ•œ๋‹ค (fixture ํŒจํ‚ค์ง€, member.fixture ํŒจํ‚ค์ง€) MemberFixture๋Š” ํ•˜๋‚˜๋กœ ํ†ต์ผํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค

Fixture ๋ฉ”์„œ๋“œ๋ช… ํ†ต์ผ

Fixture ๋งˆ๋‹ค ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ๋ช…์ด ๋‹ค๋ฅด๋‹ค ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋“ค์„ ํ†ต์ผํ•˜๋ฉด ์ถ”ํ›„ ์žฌ์‚ฌ์šฉํ•  ๋•Œ ํŽธ๋ฆฌํ•  ๊ฒƒ ๊ฐ™๋‹ค.

๋‚ด๊ฐ€ ์ œ์•ˆํ•˜๋Š” ์ด๋ฆ„์€ ๊ฒฐ๊ตญ์—” ๋ชจ๋“  ๋ฉ”์„œ๋“œ๊ฐ€ ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ์ด๋‹ˆ ์ •ํŒฉ๋ฉ” ์ด๋ฆ„ ๊ทœ์น™์„ ๋”ฐ๋ฅด๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

์ถ”๊ฐ€์ ์œผ๋กœ Fixture ๋ฅผ ์ƒ์„ฑ์ž๋กœ ์‚ฌ์šฉํ•  ์ผ์ด ์—†์„ ๊ฒƒ ๊ฐ™์œผ๋‹ˆ private๋กœ ์ƒ์„ฑ์ž๋ฅผ ๋ง‰๋Š” ๊ฑด ์–ด๋–ค๊ฐ€์š”?

jminkkk commented 2 months ago

CategoryTemplateApplicationService๋ฅผ ์ œ๊ฑฐ

ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด ์–ด๋–ค ๊ฒƒ์„ ํ…Œ์ŠคํŠธ ํ•ด์•ผํ•˜๋Š”์ง€, ์ด ๊ณ„์ธต์˜ ์—ญํ• ์€ ๋ฌด์—‡์ธ์ง€ ๊ณ ๋ฏผํ–ˆ์Šต๋‹ˆ๋‹ค. MemberTemplateApplicationService์—์„œ ๋‹จ๊ฑด ์กฐํšŒ ๊ฐ™์ด ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๋Š” ๊ณณ์— ์˜์กด์„ฑ์ด ์ œ๊ฑฐ๋˜๊ธด ํ•˜๋‚˜, MemberTemplateApplicationService๊ฐ€ ๊ฒฐ๊ณผ์ ์œผ๋กœ TemplateApplicationService๋ฅผ ๋‘ ๋ฒˆ ์˜์กดํ•˜๊ณ  ์žˆ๋Š” ๋“ฑ ๊ตฌ์กฐ๊ฐ€ ๋งค์šฐ ๋ณต์žกํ•˜๋‹ค.

์ œ๊ฐ€ ์ƒ๊ฐํ•˜๊ธฐ์— ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•

  1. ์˜์กด์„ฑ ์ œ๊ฑฐ๋ฅผ ์šฐ์„ ์œผ๋กœ ์ฑ™๊ธด๋‹ค.
    • ํ˜„์žฌ๋„ ์˜์กด์„ฑ ์ œ๊ฑฐ๊ฐ€ ์™„๋ฒฝํ•˜๊ฒŒ ๋˜์–ด์žˆ์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐ
    • ํด๋ฆฐ ์•„ํ‚คํ…์ฒ˜(์ •ํ™•ํžˆ๋Š” ํ—ฅ์‚ฌ๊ณ ๋‚ )๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๊ฐ ์œ ์Šค์ผ€์ด์Šค(์š”๊ตฌ์‚ฌํ•ญ ex. ํ…œํ”Œ๋ฆฟ ์ƒ์„ฑ)๋ณ„ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ ๋‹ค. ํด๋ฆฐ์•„ํ‚คํ…์ฒ˜, ์‚ฌ์šฉ ์˜ˆ์‹œ ๊นƒํ—ˆ๋ธŒ (ํด๋ฆฐ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋„์ž…ํ•˜์ž๋Š” ๊ฒƒ์ด ์•„๋‹˜. usecase๋งŒ ์–˜๊ธฐํ•˜๋Š” ๊ฒƒ์ž„)
    • ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ํ•ด๋‹น ์š”๊ตฌ์‚ฌํ•ญ์—์„œ ํ•„์š”ํ•œ ๊ฒƒ๋“ค๋งŒ ์˜์กดํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ช…ํ™•ํ•ด์ง„๋‹ค.
  2. ์˜์กด์„ฑ์„ ์กฐ๊ธˆ ์–‘๋ณดํ•˜๊ณ  ํ˜„์žฌ ์„œ๋น„์Šค์˜ ๋ณต์žก๋„ ๋‚ฎ์ถ˜๋‹ค.
    • CategoryTemplateApplicationService ๋“ฑ ์ค‘๊ฐ„ ํŒŒ์‚ฌ๋“œ(?)๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๊ฐ ๋„๋ฉ”์ธ ์ค‘ ์—ฌ๋Ÿฌ ๋„๋ฉ”์ธ์˜ ์˜์กด์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ, ์ƒ์œ„ ํ•˜๋‚˜์˜ ํŒŒ์‚ฌ๋“œ๋งŒ ๋†“๋Š”๋‹ค.
HoeSeong123 commented 2 months ago

TemplateService๋กœ ๋„˜์–ด์˜ค๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ๋ณ€๊ฒฝ

AS-IS

TemplateService์˜ createTemplate() ๋ฉ”์„œ๋“œ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

public Template createTemplate(Member member, CreateTemplateRequest createTemplateRequest, Category category) {
    Template template = new Template(
            member,
            createTemplateRequest.title(),
            createTemplateRequest.description(),
            category);
    return templateRepository.save(template);
}

CreateTemplateRequest์—๋Š” title, description, sourceCodes, categoryId ๋“ฑ ๋‹ค์–‘ํ•œ ํ•„๋“œ๋“ค์ด ์กด์žฌํ•˜์ง€๋งŒ ํ•ด๋‹น ๋ฉ”์†Œ๋“œ์—์„œ๋Š” title๊ณผ description๋งŒ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ•„๋“œ๋“ค์€ Templateservice์˜ ์ƒ์œ„ ํด๋ž˜์Šค๋“ค์—์„œ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค.

TO-BE

public Template createTemplate(Member member, String title, String description, Category category) {
    Template template = new Template(
            member,
            title,
            description,
            category);
    return templateRepository.save(template);
}
HoeSeong123 commented 2 months ago

๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” JPA ์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ๋ช… ๋ณ€๊ฒฝ

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

AS-IS

public List<Template> getByMemberId(Long memberId) {
    return templateRepository.findByMemberId(memberId);
}

TO-BE

public List<Template> getAllByMemberId(Long memberId) {
    return templateRepository.findAllByMemberId(memberId);
}

(์—ฌ๊ธฐ๋Š” ๋ชฐ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€ํ•จ)

์ดˆ๋กฑ์˜ ์ด์Šˆ์™€ ๋™์ผํ•œ ์ด์œ ๋กœ TemplateTagService๋„ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค~

AS-IS

    public List<Tag> getByTemplate(Template template) {
        return templateTagRepository.findAllByTemplate(template).stream()
                .map(TemplateTag::getTag)
                .toList();
    }

TO-BE

    public List<Tag> getAllByTemplate(Template template) {
        return templateTagRepository.findAllByTemplate(template).stream()
                .map(TemplateTag::getTag)
                .toList();
    }
HoeSeong123 commented 2 months ago

์ค‘๋ณต๊ฒ€์‚ฌ ๋กœ์ง

AS-IS

ํ˜„์žฌ ์—ฌ๋Ÿฌ ํ…œํ”Œ๋ฆฟ ์‚ญ์ œ ์‹œ ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š”๋ฐ, id๊ฐ€ ์ค‘๋ณต๋˜์–ด ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•˜๋Š” ๋กœ์ง์ด TemplateService์—๋งŒ ์œ„์น˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

// TemplateApplicationService.java

@Transactional
public void deleteByMemberAndIds(Member member, List<Long> ids) {
    thumbnailService.deleteByTemplateIds(ids);
    sourceCodeService.deleteByIds(ids);
    templateTagService.deleteByIds(ids);
    templateService.deleteByMemberAndIds(member, ids);
}
// TemplateService.java

@Transactional
public void deleteByMemberAndIds(Member member, List<Long> ids) {
    if (ids.size() != new HashSet<>(ids).size()) {
        throw new CodeZapException(HttpStatus.BAD_REQUEST, "์‚ญ์ œํ•˜๊ณ ์ž ํ•˜๋Š” ํ…œํ”Œ๋ฆฟ ID๊ฐ€ ์ค‘๋ณต๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
    }
    ids.forEach(id -> deleteById(member, id));
}

๋ชจ๋“  ์‚ญ์ œ ๋กœ์ง ์ „์— ๊ฒ€์ฆ์ด ์šฐ์„ ๋˜์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์—ฌ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ€๊ฒฝ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค.

TO-BE

// TemplateApplicationService.java

@Transactional
public void deleteByMemberAndIds(Member member, List<Long> ids) {
     if (ids.size() != new HashSet<>(ids).size()) {
        throw new CodeZapException(HttpStatus.BAD_REQUEST, "์‚ญ์ œํ•˜๊ณ ์ž ํ•˜๋Š” ํ…œํ”Œ๋ฆฟ ID๊ฐ€ ์ค‘๋ณต๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
    }
    thumbnailService.deleteByTemplateIds(ids);
    sourceCodeService.deleteByIds(ids);
    templateTagService.deleteByIds(ids);
    templateService.deleteByMemberAndIds(member, ids);
}
HoeSeong123 commented 2 months ago

์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋ฉ”์†Œ๋“œ

ThumbnailSerivce์—์„œ ์ „์ฒด ์ธ๋„ค์ผ์„ ์กฐํšŒํ•˜๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ์‚ฌ์šฉ๋˜์ง€ ์•Š๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์— ์‚ญ์ œ๋ฅผ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค.

public ExploreTemplatesResponse findAll() {
    return ExploreTemplatesResponse.from(thumbnailRepository.findAll());
}

์™ธ์—๋„ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋ฉ”์†Œ๋“œ๋“ค์ด ๋‹ค์†Œ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ „์ฒด์ ์œผ๋กœ ํ•œ ๋ฒˆ ํ™•์ธํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.


(์—ฌ๊ธฐ๋Š” ๋ชฐ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€ํ•จ)

์ดˆ๋กฑ์˜ ์ด์Šˆ์™€ ๋™์ผํ•œ ์ด์œ ๋กœ TemplateTagService๋„ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค~

TemplateTagService์˜ getTemplateIdContainTagIds์ด ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋˜ getTemplateIdContainTagIds์˜ ๋ฐ˜ํ™˜ ๊ฐ’์ด TemplateId์ธ๋ฐ, TemplateTagService์—์„œ TemplateId๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒŒ ์‚ฌ์šฉ์ด ์–ด์ƒ‰ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

    public List<Long> getTemplateIdContainTagIds(List<Long> tagIds) {
        if (tagIds.isEmpty()) {
            throw new CodeZapException(HttpStatus.BAD_REQUEST, "ํƒœ๊ทธ ID๊ฐ€ 0๊ฐœ์ž…๋‹ˆ๋‹ค. ํ•„ํ„ฐ๋ง ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ null๋กœ ์ „๋‹ฌํ•ด์ฃผ์„ธ์š”.");
        }
        tagIds.forEach(this::validateTagId);
        return templateTagRepository.findAllTemplateIdInTagIds(tagIds, tagIds.size());
    }

    private void validateTagId(Long tagId) {
        if (!tagRepository.existsById(tagId)) {
            throw new CodeZapException(HttpStatus.NOT_FOUND, "์‹๋ณ„์ž " + tagId + "์— ํ•ด๋‹นํ•˜๋Š” ํƒœ๊ทธ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
        }
    }
jminkkk commented 2 months ago

ํƒฌํ”Œ๋ฆฟ ํƒœ๊ทธ ์‚ญ์ œ๋กœ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ํƒœ๊ทธ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ

์ผ๋‹จ TemplateTagService๋Š” TagService ์šฉ๋„๋กœ๋„ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. (Tag ๋ชฉ๋ก ์กฐํšŒ ๋“ฑ๋“ฑ) TemplateTagService์—์„œ ํ…œํ”Œ๋ฆฟ๋“ค์— ๋Œ€ํ•œ ํ…œํ”Œ๋ฆฟ ํƒœ๊ทธ ์‚ญ์ œ ์‹œ ํ•œ๊ฐœ๋„ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ํƒœ๊ทธ์ธ ๊ฒฝ์šฐ ํƒœ๊ทธ๋„ ํ•จ๊ป˜ ์ œ๊ฑฐ๋˜์–ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ex) "Moly"๋ผ๋Š” ํƒœ๊ทธ๊ฐ€ template1, template2์—์„œ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ, ๋‘ ํ…œํ”Œ๋ฆฟ์— ํ•ด๋‹นํ•˜๋Š” ํƒœ๊ทธ ๋ชฉ๋ก ์‚ญ์ œ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๊ฒฝ์šฐ "template1, Moly", "template2, Moly"๋ผ๋Š” ํ…œํ”Œ๋ฆฟ ํƒœ๊ทธ๋Š” ์‚ญ์ œ ๋˜์ง€๋งŒ, "Moly"๋ผ๋Š” ํƒœ๊ทธ๋Š” ๊ณ„์†ํ•ด์„œ ๋‚จ์•„์žˆ์Šต๋‹ˆ๋‹ค.

AS-IS

// TemplateTagService.java
    public void deleteByIds(List<Long> templateIds) {
        templateIds.forEach(templateTagRepository::deleteAllByTemplateId);
    }

TO-BE

// TemplateTagApplicationService.java
    public void deleteByIds(List<Long> templateIds) {
        List<Tag> notUsedTags = templateTagService.deleteAllByTemplate(templateIds);
        tagService.deleteIfNotUsed(notUsedTags);
    }

// TemplateTagService.java
    public void deleteAndCollectUnused(List<Long> templateIds) {
        // 1. ํƒœ๊ทธ๋กœ ํ…œํ”Œ๋ฆฟ ํ…Œ๊ทธ ์กฐํšŒ 
        // 2. ํ…œํ”Œ๋ฆฟ ํƒœ๊ทธ ์‚ญ์ œ ๋ฐ ํƒœ๊ทธ ๋ชฉ๋ก ๋ฐ˜ํ™˜
        // 3. ํƒœ๊ทธ๋“ค ์ค‘ ๋‹ค๋ฅธ ํ…œํ”Œ๋ฆฟ์— ์‚ฌ์šฉ๋˜๋Š” ํƒœ๊ทธ๋“ค ์ œ์™ธ
        // 4. ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ํƒœ๊ทธ ๋ชฉ๋ก ๋ฐ˜ํ™˜ 
    }

// TagService.java
    public void deleteIfNotUsed(List<Tag> tags) {
        // 1. ํƒœ๊ทธ ์‚ญ์ œ
    }
zeus6768 commented 2 months ago

Member.equals() ์—์„œ ํด๋ž˜์Šค ๋น„๊ต ์ œ๊ฑฐ

ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ Category ์˜ ํ•„๋“œ๋กœ ์‚ฌ์šฉ๋˜๊ณ , lazy loading ์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ ํ”„๋ก์‹œ ๊ฐ์ฒด์™€ Member ๊ฐ์ฒด์˜ ๋™๋“ฑ์„ฑ ๋น„๊ต๊ฐ€ ์ƒ๊ธด๋‹ค. ์ด ๋•Œ๋ฌธ์— ํด๋ž˜์Šค ๋น„๊ต๋ฅผ ์ œ๊ฑฐํ•ด์•ผ ํ•œ๋‹ค.

if (o == null || getClass() != o.getClass()) {
    return false;
}

(ํ•ด๋‹น ์ฝ”๋ฉ˜ํŠธ ๊ด€๋ จ)

664

zeus6768 commented 2 months ago

FindTemplateResponse` ํด๋ž˜์Šค๋ช… ๋ณ€๊ฒฝ ์ œ์•ˆ

ํ•ด๋‹น DTO๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๋ชจ๋“  ๋ฉ”์„œ๋“œ๋ช…์˜ prefix๊ฐ€ get์ธ ๋ฐ˜๋ฉด, ํด๋ž˜์Šค๋ช…dml prefix๊ฐ€ Find์—ฌ์„œ ๊ฐ€๋…์„ฑ์„ ์ €ํ•ดํ•ฉ๋‹ˆ๋‹ค.


(์ผฌ๋ฏธ๊ฐ€ ์ด์–ด์”€)

find vs get vs fetch ๋ฉ”์„œ๋“œ๋ช… ํ†ต์ผ

์กฐํšŒ ๋ฉ”์„œ๋“œ์˜ prefix๋ฅผ ํ†ต์ผํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์š” ์ผฌ๋ฏธ ๊ฐœ์ธ ์„ ํ˜ธ์— ๋”ฐ๋ฅธ ๋ณ€๊ฒฝ

MemberCategoryApplicationService
kyum-q commented 2 months ago

๋ฉ”์„œ๋“œ๋ช… ๋์— By ๊ตฌ๋ฌธ ํ†ต์ผ์„ฑ ํ•„์š”

์ผ๋ถ€ ๋ฉ”์„œ๋“œ๋Š” create๋งŒ ์‚ฌ์šฉํ•œ๋‹ค image

์ผ๋ถ€ ๋ฉ”์„œ๋“œ๋Š” create ์ดํ›„ ์ธ์ž๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค image

ํ†ต์ผํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค

jminkkk commented 2 months ago

SourceCode ์‚ญ์ œ or ์กฐํšŒ

zangsu commented 2 months ago

์—”ํ‹ฐํ‹ฐ๋กœ ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ ์ˆ˜์ •

CategoryService.findAllByMember() -> InvalidDataAccessApiUsageException ๋ฐœ์ƒ Member member ๋Œ€์‹  long memberId ๋กœ ์กฐํšŒํ•˜๋ฉด DB ์˜ˆ์™ธ๊ฐ€ ์•„๋‹Œ java.util.NoSuchElementException ๋ฐœ์ƒ ์ด์— ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ, id ๊ฐ’์œผ๋กœ ์กฐํšŒํ•˜๋„๋ก ๋ณ€๊ฒฝ ์ œ์•ˆ