Skip to content

Commit 4aaf65c

Browse files
authored
Step1 - 레거시 코드 리팩토링 (#809)
* feat : 레거시 코드 리팩터링 * 요구사항 토대로 질문, 답변의 행위 설정 * 설정된 행위들 TDD 구현 * 레포지토리 인터페이스 패키지 이관 * feat : 레거시 코드 리팩터링 * 예외객체 패키징 * 삭제이력 응답행위 질문,답변 객체에 구현 * QnADomainService 기반 도메인 로직 조합 * QnAService deleteQuestion 개선. * refactor : 레거시 코드 리팩터링 * 미사용 코드 제거 및 get/set 제거 * 테스트 코드 정리 * refactor : 레거시 코드 리팩터링 * 소프트삭제 가능 추상클래스 생성 및 질문 도메인객체에 관련 내용 적용 * refactor : 레거시 코드 리팩터링 * 소프트삭제 추상클래스 답변 도메인객체에 적용 * refactor : 레거시 코드 리팩터링 * 소프트삭제 추상클래스 네이밍 변경 * refactor : 레거시 코드 리팩터링 * 게시판 내용 객체 생성 * 질문 & 답변 객체에 적용 * refactor : 레거시 코드 리팩터링 * 로그인 키페어 객체 생성 및 회원객체에 적용 * 회원객체 불필요 코드 제거 * refactor : 레거시 코드 리팩터링 * 기본 도메인객체 추상클래스 생성 및 유저 도메인 객체에 적용 * 삭제가능 추상클래스에 id 추가 및 적용 * refactor : 레거시 코드 리팩터링 * 기본 도메인객체 추상클래스 삭제이력 도메인 객체에 적용 * 테스트 실패로 생성/수정시간 관련 로직 외부에서 주입받게 변경
1 parent de587b9 commit 4aaf65c

27 files changed

+591
-296
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package nextstep.common.domain;
2+
3+
import java.time.LocalDateTime;
4+
import java.util.Objects;
5+
6+
public abstract class BaseEntity {
7+
private Long id;
8+
private LocalDateTime createdDate;
9+
private LocalDateTime updatedDate;
10+
11+
protected BaseEntity(Long id) {
12+
this(id, LocalDateTime.now(), LocalDateTime.now());
13+
}
14+
15+
public BaseEntity(Long id, LocalDateTime createdDate, LocalDateTime updatedDate) {
16+
this.id = id;
17+
this.createdDate = createdDate;
18+
this.updatedDate = updatedDate;
19+
}
20+
21+
public Long getId() {
22+
return id;
23+
}
24+
25+
@Override
26+
public boolean equals(Object o) {
27+
if (o == null || getClass() != o.getClass()) {
28+
return false;
29+
}
30+
BaseEntity that = (BaseEntity) o;
31+
return Objects.equals(id, that.id)
32+
&& Objects.equals(createdDate, that.createdDate)
33+
&& Objects.equals(updatedDate, that.updatedDate);
34+
}
35+
36+
@Override
37+
public int hashCode() {
38+
return Objects.hash(id, createdDate, updatedDate);
39+
}
40+
41+
@Override
42+
public String toString() {
43+
return "BaseEntity{" +
44+
"id=" + id +
45+
", createdDate=" + createdDate +
46+
", updatedDate=" + updatedDate +
47+
'}';
48+
}
49+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package nextstep.common.domain;
2+
3+
import java.time.LocalDateTime;
4+
import java.util.Objects;
5+
6+
public abstract class SoftDeletableBaseEntity {
7+
private Long id;
8+
private boolean deleted;
9+
private LocalDateTime createdDate;
10+
private LocalDateTime updatedDate;
11+
12+
protected SoftDeletableBaseEntity(Long id) {
13+
this(id, false, LocalDateTime.now(), LocalDateTime.now());
14+
}
15+
16+
protected SoftDeletableBaseEntity(Long id, LocalDateTime createdAt, LocalDateTime updatedAt) {
17+
this(id, false, createdAt, updatedAt);
18+
}
19+
20+
protected SoftDeletableBaseEntity(Long id, boolean deleted, LocalDateTime createdDate,
21+
LocalDateTime updatedDate) {
22+
this.id = id;
23+
this.deleted = deleted;
24+
this.createdDate = createdDate;
25+
this.updatedDate = updatedDate;
26+
}
27+
28+
protected boolean isDeleted() {
29+
return this.deleted;
30+
}
31+
32+
public void updateDeleted() {
33+
this.deleted = true;
34+
}
35+
36+
public Long getId() {
37+
return id;
38+
}
39+
40+
@Override
41+
public boolean equals(Object o) {
42+
if (o == null || getClass() != o.getClass()) {
43+
return false;
44+
}
45+
SoftDeletableBaseEntity that = (SoftDeletableBaseEntity) o;
46+
return deleted == that.deleted
47+
&& Objects.equals(id, that.id)
48+
&& Objects.equals(createdDate, that.createdDate)
49+
&& Objects.equals(updatedDate, that.updatedDate);
50+
}
51+
52+
@Override
53+
public int hashCode() {
54+
return Objects.hash(id, deleted, createdDate, updatedDate);
55+
}
56+
}
Lines changed: 35 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,58 @@
11
package nextstep.qna.domain;
22

3-
import nextstep.qna.NotFoundException;
4-
import nextstep.qna.UnAuthorizedException;
5-
import nextstep.users.domain.NsUser;
6-
73
import java.time.LocalDateTime;
8-
9-
public class Answer {
10-
private Long id;
11-
12-
private NsUser writer;
13-
4+
import nextstep.common.domain.SoftDeletableBaseEntity;
5+
import nextstep.qna.exception.unchecked.CannotDeleteException;
6+
import nextstep.qna.exception.unchecked.NotFoundException;
7+
import nextstep.qna.exception.unchecked.UnAuthorizedException;
8+
import nextstep.qna.exception.unchecked.WrongRequestException;
9+
10+
public class Answer extends SoftDeletableBaseEntity {
11+
private Long writerId;
1412
private Question question;
13+
private BoardContent boardContent;
1514

16-
private String contents;
17-
18-
private boolean deleted = false;
19-
20-
private LocalDateTime createdDate = LocalDateTime.now();
21-
22-
private LocalDateTime updatedDate;
23-
24-
public Answer() {
15+
public Answer(long writerId, Question question, String contents) {
16+
this(null, writerId, question, contents);
2517
}
2618

27-
public Answer(NsUser writer, Question question, String contents) {
28-
this(null, writer, question, contents);
29-
}
30-
31-
public Answer(Long id, NsUser writer, Question question, String contents) {
32-
this.id = id;
33-
if(writer == null) {
19+
public Answer(Long id, long writerId, Question question, String contents) {
20+
super(id);
21+
if (writerId <= 0L) {
3422
throw new UnAuthorizedException();
3523
}
3624

37-
if(question == null) {
25+
if (question == null) {
3826
throw new NotFoundException();
3927
}
4028

41-
this.writer = writer;
29+
this.writerId = writerId;
4230
this.question = question;
43-
this.contents = contents;
31+
this.boardContent = new BoardContent("" , contents);
4432
}
4533

46-
public Long getId() {
47-
return id;
34+
public boolean isDeleted() {
35+
return super.isDeleted();
4836
}
4937

50-
public Answer setDeleted(boolean deleted) {
51-
this.deleted = deleted;
52-
return this;
53-
}
38+
public void putOnDelete(long requesterId) {
39+
if (!isOwner(requesterId)) {
40+
throw new CannotDeleteException("질문을 삭제할 권한이 없습니다.");
41+
}
5442

55-
public boolean isDeleted() {
56-
return deleted;
43+
super.updateDeleted();
5744
}
5845

59-
public boolean isOwner(NsUser writer) {
60-
return this.writer.equals(writer);
46+
public boolean isOwner(long writerId) {
47+
return this.writerId == writerId;
6148
}
6249

63-
public NsUser getWriter() {
64-
return writer;
65-
}
50+
public DeleteHistory createAnswerDeleteHistory(LocalDateTime deletedDateTime) {
51+
if (!isDeleted()) {
52+
throw new WrongRequestException("삭제되지 않은 답변은 삭제이력을 생성할 수 없습니다.");
53+
}
6654

67-
public String getContents() {
68-
return contents;
55+
return new DeleteHistory(ContentType.ANSWER, super.getId(), this.writerId, deletedDateTime);
6956
}
7057

7158
public void toQuestion(Question question) {
@@ -74,6 +61,9 @@ public void toQuestion(Question question) {
7461

7562
@Override
7663
public String toString() {
77-
return "Answer [id=" + getId() + ", writer=" + writer + ", contents=" + contents + "]";
64+
return "Answer [id=" + super.getId()
65+
+ ", writerId=" + writerId
66+
+ ", contents=" + boardContent
67+
+ "]";
7868
}
7969
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package nextstep.qna.domain;
2+
3+
public class BoardContent {
4+
private String title;
5+
private String contents;
6+
7+
public BoardContent(String title, String contents) {
8+
this.title = title;
9+
this.contents = contents;
10+
}
11+
12+
@Override
13+
public String toString() {
14+
return "BoardContent{" +
15+
"title='" + title + '\'' +
16+
", contents='" + contents + '\'' +
17+
'}';
18+
}
19+
}
Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,53 @@
11
package nextstep.qna.domain;
22

3+
import static java.util.Objects.*;
4+
5+
import nextstep.common.domain.BaseEntity;
36
import nextstep.users.domain.NsUser;
47

58
import java.time.LocalDateTime;
69
import java.util.Objects;
710

8-
public class DeleteHistory {
9-
private Long id;
10-
11+
public class DeleteHistory extends BaseEntity {
1112
private ContentType contentType;
12-
1313
private Long contentId;
14+
private Long deletedId;
1415

15-
private NsUser deletedBy;
16-
17-
private LocalDateTime createdDate = LocalDateTime.now();
18-
19-
public DeleteHistory() {
16+
public DeleteHistory(ContentType contentType, Long contentId, Long deletedId, LocalDateTime createdDate) {
17+
this(0L, contentType, contentId, deletedId, createdDate, null);
2018
}
2119

22-
public DeleteHistory(ContentType contentType, Long contentId, NsUser deletedBy, LocalDateTime createdDate) {
20+
public DeleteHistory(Long id, ContentType contentType, Long contentId, Long deletedId, LocalDateTime createdDate, LocalDateTime updateDate) {
21+
super(id, createdDate, updateDate);
2322
this.contentType = contentType;
2423
this.contentId = contentId;
25-
this.deletedBy = deletedBy;
26-
this.createdDate = createdDate;
24+
this.deletedId = deletedId;
2725
}
2826

2927
@Override
3028
public boolean equals(Object o) {
31-
if (this == o) return true;
32-
if (o == null || getClass() != o.getClass()) return false;
29+
if (o == null || getClass() != o.getClass()) {
30+
return false;
31+
}
3332
DeleteHistory that = (DeleteHistory) o;
34-
return Objects.equals(id, that.id) &&
35-
contentType == that.contentType &&
36-
Objects.equals(contentId, that.contentId) &&
37-
Objects.equals(deletedBy, that.deletedBy);
33+
return super.equals(o)
34+
&& contentType == that.contentType
35+
&& Objects.equals(contentId, that.contentId)
36+
&& Objects.equals(deletedId, that.deletedId);
3837
}
3938

4039
@Override
4140
public int hashCode() {
42-
return Objects.hash(id, contentType, contentId, deletedBy);
41+
return hash(super.hashCode(), contentType, contentId, deletedId);
4342
}
4443

4544
@Override
4645
public String toString() {
47-
return "DeleteHistory [id=" + id + ", contentType=" + contentType + ", contentId=" + contentId + ", deletedBy="
48-
+ deletedBy + ", createdDate=" + createdDate + "]";
46+
return "DeleteHistory{" +
47+
"id=" + super.toString() +
48+
", contentType=" + contentType +
49+
", contentId=" + contentId +
50+
", deletedId=" + deletedId +
51+
'}';
4952
}
5053
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package nextstep.qna.domain;
2+
3+
import java.time.LocalDateTime;
4+
import java.util.List;
5+
6+
public class QnADomainService {
7+
8+
// TODO : 피드백 주신 부분 잘보았습니다.
9+
// 저는 개인적으로 도메인 로직은 순수하게 유지하는게 가장 좋다고 생각합니다만.
10+
// 스프링을 활용한 의존성주입이 필요한 예외적인 상황(불가피한 외부API 호출, 이메일 등등..)에서는 허용하고 사용해주는것도 좋다고 생각합니다.
11+
// 다만 단계를 거쳐볼것 같아요. 1. 순수 객체 -> 2. 클래스 메서드(static) 집합 객체(=외부 bean 필요없이 캐싱 작업이 필요힌 경우) -> 3. 외부 bean이 불가피하게 필요한경우 bean & di
12+
public List<DeleteHistory> deleteQuestion(
13+
long requesterId, Question question, LocalDateTime fixedDeletedDateTime
14+
) {
15+
question.putOnDelete(requesterId);
16+
17+
return question.bringAllDeleteHistories(fixedDeletedDateTime);
18+
}
19+
}

0 commit comments

Comments
 (0)