-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Zzazan] 1주차 zzazanstagram 기능 구현 #4
Conversation
[#18] feat: 공통 패키지 및 엔티티 정의
1. Article 엔티티 클래스를 추가한다 2. Article 엔티티의 하위 VO 클래스를 추가한다 3. 그래들에 의존성을 추가한다
Feature/14 article frontend
Closes #8
Feature/6 member setting
1. 게시글을 작성하는 기능을 추가한다 1-1. ArticleController 클래스를 추가한다 1-2. POST 요청 시, 작성된 게시글을 저장한다 1-3. ArticleRequest DTO 클래스를 추가한다 1-4. ArticleRepository 클래스를 추가한다 2. 게시글 작성 기능에 대한 컨트롤러의 테스트 메서드를 추가한다
[#15] 게시글 작성 기능 구현 PR
[#26] refactor: 8월 13일 리뷰에 따른 리팩토링 적용
Closes #10
1. ArticleAssembler 클래스에 DTO로 변환하는 메서드를 추가한다 2. ArticleController에서 서비스 로직을 분리한다 3. 불필요한 어노테이션을 삭제한다
[#15] 게시글 조회 기능 구현 PR
Feature/6 signup frontend
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
코드 깔끔하게 잘 구현하셨어요 👍
패키지는 지금 구조로 가도 괜찮을 것 같네요
좀더 분리하자면 controller, (컨트롤러에서 사용하는)dto, member session 같이 표현 계층과 관련있는 패키지는 web으로 옮길 수도 있습니다.
몇 가지 코멘트 남겼으니 참고하시고 궁금한 점 있으면 코멘트 남기시거나 dm 주세요
@JoinColumn(name = "author", nullable = false, foreignKey = @ForeignKey(name = "fk_article_to_member")) | ||
private Member author; | ||
|
||
protected Article() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
상속을 허용하는게 아니라면 private 접근제어자를 추천드립니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
하이버네이트에서 지연로딩을 구현할 때 엔티티 클래스를 상속해서 프록시 객체를 만든다고 알고 있습니다!
그래서 기본 생성자에 private을 지정해두게 되면 프록시 클래스에서 상속을 받지 못하기 때문에 protected로 두었습니다~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 맞네요 그부분을 제가 놓쳤네요 👍
this.author = author; | ||
} | ||
|
||
public static Article from(final Image image, final Contents contents, final Member author) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
지금은 생성자로 충분해 보이는데 팩토리 메서드를 따로 만든 이유가 있을까요?
import javax.persistence.Lob; | ||
|
||
@Embeddable | ||
public class Contents { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Contents를 클래스로 새로 정의할 필요가 있을까요?
Article 클래스에서 String contents 필드로 작성하면 코드가 더 간결해지지 않을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Contents를 일급컬렉션으로 빼놓은 이유는 필드를 일관성 있게 구성하고 싶어서 였습니다!
만약 어떤 필드는 원시타입으로 관리하고 있는데 다른 필드가 일급컬렉션으로 관리하고 있다면 데이터를 관리할 때 혼란스러울 것이라고 생각했습니다 :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
일급컬렉션이요? wrapper class를 말씀하신걸까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
데이터 관리할 때 어떤 점이 어려울지 잘 모르겠네요;
예시나 좀더 자세한 상황을 알려주실 수 있을까요?
|
||
private String validateUrl(final String url) { | ||
try { | ||
HttpURLConnection.setFollowRedirects(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이미지가 http가 아닌 ftp에 있다면?
다른 통신 방법을 이용해야된다면 http에 의존하는 이 코드가 문제가 되지 않을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 부분은 저희가 차후에 S3를 사용해서 이미지 파일을 관리할 예정에 있기 때문에 ftp는 고려하지 않았습니다!
하지만 나중에 다른 기능을 구현하는 경우에는 이런 부분도 생각을 해봐야겠네요.
알려주셔서 감사합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
크롬이 이제 ftp 지원을 안한다고 합니다 ㅎㅎ; 그러니 저희도.. 😏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ftp는 예시구요, 도메인 코드에서 유효성 체크를 위해 http 통신을 할 필요가 있냐는 의견이에요
표현 계층에서 이미지가 존재하는지 결정해도 충분하지 않나요?
지금 이 유효성 체크는 이미지를 호출하는 외부 서비스가 응답이 없으면 같이 영향을 받습니다.
차라리 프론트에서 이미지를 못 불러오더라도 다른 기능은 동작하도록 하고, 이 객체는 이미지 위치만 전달하는 역할만 해도 충분해보입니다.
private String image; | ||
|
||
private String contents; | ||
private String hashTag; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 필드와 관련된 기능은 추가 예정인거죠? article 클래스에서 아직 관련 기능이 안보이네요 ㅎㅎ;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵 :-D
도메인 설계는 거시적으로 생각하긴 했는데 한 번에 적용할 수는 없을 것 같아서 선언만 해놓았어요~
|
||
private String validateUrl(final String url) { | ||
try { | ||
HttpURLConnection.setFollowRedirects(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
인프라스트럭처 계층 코드가 있네요
return url; | ||
} | ||
|
||
public ProfileImage updateUrl(String url) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
메서드명으로 update가 적절해보이진 않네요
valueOf 같이 불변 객체를 생성하는 의미가 담긴 메서드명을 찾아보는건 어떨까요
@@ -0,0 +1,10 @@ | |||
package com.woowacourse.zzazanstagram.model.member.exception; | |||
|
|||
public class MemberException extends IllegalArgumentException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Member와 관련된 모든 오류를 이 예외에서 다 처리하지 말고 좀더 세분화해보는건 어떨까요?
회원 로그인 시도할 때 비밀번호가 틀렸을 때 예외, 회원을 찾을 수 없을 때 발생하는 예외 등등으로 나누면 에러 메시지에 의존하지 않고 어떤 이슈인지 빠르게 파악 가능할거에요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MemberException 세분화 잘 하셨어요 👍
그런데 MemberException이 IllegalArgumentException를 상속하는게 맞을까요?
} | ||
} | ||
|
||
private void checkEnrolledNickName(String nickName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
boolean existsByNickName(NickName nickName);
이 메서드를 memberRepository에 추가하면 코드가 좀더 간결해질거에요
} | ||
|
||
@ParameterizedTest | ||
@ValueSource(strings = {"https://image.shutterstock.com/image-photo/white-transparent-leaf-on-mirror-600w-1029171697.jpg", "https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-600w-1048185397.jpg"}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ValueSource(strings = {"https://image.shutterstock.com/image-photo/white-transparent-leaf-on-mirror-600w-1029171697.jpg", "https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-600w-1048185397.jpg"}) | |
@ValueSource(strings = { | |
"https://image.shutterstock.com/image-photo/white-transparent-leaf-on-mirror-600w-1029171697.jpg", | |
"https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-600w-1048185397.jpg" | |
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IDE를 사용하시면 보이는 세로선은 이 margin까지만 코드를 작성하자는 컨벤션같은건데요.
옆으로 코드가 나열되면 가독성이 떨어집니다. 보통은 80 ~ 100이 기본입니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테스트코드 깔끔하게 잘 작성하셨네요! 💯
그리고 이슈도 잘 정리하고 있는 것으로 보이는데요.
칸반보드를 활용하지 않다보니 현재 진행중인 이슈는 무엇인지 확인하기가 어렵네요 ㅠㅠ
혹시 Projects 탭을 활용하지 않는 이유가 있을까요?
mavenCentral() | ||
} | ||
|
||
dependencies { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gradlew 로 build 실행시에는 테스트를 skip하고 있어요.
아래 설정 추가한 이후에 배포해보시겠어요?
test {
useJUnitPlatform()
}
...
dependencies {
...
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
} | ||
|
||
public String image() { | ||
return image.getUrl(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
method name은 동작을 구체적으로 드러내는 동사를 사용하시는 것이 좋다고 생각합니다.
http://www.mimul.com/pebble/default/2013/05/04/1367639300999.html
import javax.persistence.Lob; | ||
|
||
@Embeddable | ||
public class Contents { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
일급컬렉션이요? wrapper class를 말씀하신걸까요?
@@ -0,0 +1,44 @@ | |||
package com.woowacourse.zzazanstagram.model.article.domain.vo; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
model pacakge 하위에 controller, service, domain package가 있군요 🤔
try { | ||
HttpURLConnection.setFollowRedirects(false); | ||
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection(); | ||
con.setRequestMethod("HEAD"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Image class에서 URL 리소스의 유효성을 검증하는 것이 좋을까요?
Image model이 HttpURLConnection class와 연관관계를 가지는 것보다
Image 도메인 모델의 생애주기를 관리하는 repository의 구현체, 혹은 dao 등과 연관관계를 가지는 것은 어떨까요?
return name; | ||
} | ||
|
||
public Name updateName(String name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name class이니, validateName, updatName 등의 Name도 중복이지 않을까요? 🙄
try { | ||
HttpURLConnection.setFollowRedirects(false); | ||
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection(); | ||
con.setRequestMethod("HEAD"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Image class에 있는 로직과 중복이네요..? 🙄
|
||
public void save(MemberSignUpRequest memberSignupRequest) { | ||
checkEnrolledEmail(memberSignupRequest.getEmail()); | ||
checkEnrolledNickName(memberSignupRequest.getNickName()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
매번 저장할때마다 조회쿼리가 여러번 발생하겠군요. 🙄
@ActiveProfiles("test") | ||
@AutoConfigureWebTestClient | ||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) | ||
public abstract class RequestTemplate { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
} | ||
|
||
@ParameterizedTest | ||
@ValueSource(strings = {"https://image.shutterstock.com/image-photo/white-transparent-leaf-on-mirror-600w-1029171697.jpg", "https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-600w-1048185397.jpg"}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IDE를 사용하시면 보이는 세로선은 이 margin까지만 코드를 작성하자는 컨벤션같은건데요.
옆으로 코드가 나열되면 가독성이 떨어집니다. 보통은 80 ~ 100이 기본입니다.
앗 내부적으로 ZenHub 사용해서 칸반보드 관리하고 있습니다! :) 기능이 많아서 좋은데 외부에선 보이지 않는다는 단점이 있네요ㅜㅜ |
기존에 gradlew 로 build 실행시에는 테스트를 skip하고 있어서 https://www.baeldung.com/junit-5-gradle 를 참고하여 의존성 추가
기존의 existsByEmail, existsByNickName메서드를 통해서 각각 쿼리를 날리던 상황에서 existsByNickNameOrEmail를 사용하여 한 번만 쿼리를 날리도록 수정
Article, Member 클래스에서 Vo의 String 값을 요청하는 메서드명을 동사로 수정
리뷰 주셔서 감사합니다! 주신 피드백은 모두 적용하였는데 구조화 작업은 아직 자바스크립트 실력이 부족하여 진행하지 못하였습니다ㅠㅠ 공부를 조금 더 하고나서 적용해 보겠습니다...! |
[#57] refactor: 8/17 씨유 코치님 리뷰 반영
[DEMO] ver.0.0.2 merge (0.0.1 refactor)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
피드백 반영 잘 하셨어요 👍
몇 가지 추가 코멘트 남긴 건 참고하시고 다음 단계 진행하세요!
@@ -0,0 +1,10 @@ | |||
package com.woowacourse.zzazanstagram.model.member.exception; | |||
|
|||
public class MemberException extends IllegalArgumentException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MemberException 세분화 잘 하셨어요 👍
그런데 MemberException이 IllegalArgumentException를 상속하는게 맞을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗 죄송합니다 빼먹었네요 ㅠ 다시 올려놓겠습니다 |
[#60] refactor: gradle test 추가
[DEMO] hotfix v.0.0.2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아주 멋있고 아름다운 코드와 구조네요
승인합니다
[구현한 기능 목록]
패키지 구조를 어떻게 가져가야 할지 잘 몰라서 많이 고민했습니다. 패키지 구조에 대해서 조언 부탁드려요 :)
리뷰 잘 부탁드립니다-! 감사합니다~