Skip to content

Instantly share code, notes, and snippets.

@ksundong
Last active December 28, 2022 02:30
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ksundong/61efc45a1db30fcc5bbd9854b81eaed8 to your computer and use it in GitHub Desktop.
Save ksundong/61efc45a1db30fcc5bbd9854b81eaed8 to your computer and use it in GitHub Desktop.
코드스쿼드 Q&A 게시판 프로젝트 리뷰 정리

다른 분들 PR Review 보기 및 Review들의 요약

  • 직관적인 변수명의 사용. Naming을 좀 더 상세하게 해봅시다.

  • 날짜와 시간을 나타내는 클래스는 ZonedDateTime, LocalDateTime이 있는데, 이들을 언제 선택하는 지 생각해봅시다.

  • field의 타입과 getter의 타입이 다른 경우를 지양합시다. 별도의 메소드로 분리합시다.

  • handlebar에서 별도의 getter를 어떻게 호출하는지 생각해봅시다.

  • Q&A 게시판에서 중간의 질문이 삭제되고 새로운 질문이 생성되었을 때, 인덱스는 어떻게 설정되어야 할까요?

  • User의 Collection을 List로 선택한 것은 좋은 선택일까요? 더 좋은 방법은 어떤 것이 있을까요?

  • ArrayList는 여러 요청이 한 번에 들어와도 처리하는 Collection이기 때문에 더 좋은 방법을 고민해봅시다.

  • <a href="#"...은 지양해주세요. (커서의 모양을 바꾸려면 css로 바꿔주세요.)

    honux: 그러면 기능이 구현되기 이전에는 어떻게 처리해주는게 좋을까요?

  • 공통으로 사용되는 부분은 head라도 추출해주세요.

  • model은 return 'view'를 할 때에만 유효합니다.

  • viewController에서 setOrder는 왜 할까요?(공통부분 분리 후의 내용)

  • 람다식 안의 인자도 유의미한 약자를 사용합시다.

  • 값이 없을 때, null을 반환해야 할까요? 예외를 던져야 할까요? 아니면 HTTP 상태코드로 알려줄 수 있을까요? 조회할 때, 원하는 값이 없을 때, 어떻게 처리할 지 생각해봅시다.

  • @RequestMapping을 어떻게 사용하는지 이해하고 사용합시다. (메소드 명을 붙여줘야 합니다.)

    @Controller
    @RequestMapping("/공통url")
    public class 클래스명 {
        ...
        @PostMapping("/create")
    }

    이와 같은 식으로 사용하는 방법도 있습니다.

  • 파일 저장시 newline을 꼭 붙여주세요. (만약 붙이지 않는다면, 해당 라인도 변경사항에 포함됩니다.) ⌘+⇧+a ⇒ Ensure line feed at file end on Save를 켜줍시다.

  • @Controller 자체는 싱글톤이지만, 내부의 인스턴스는 thread-safe 하지 않을 수 있음을 염두에 둡시다.

  • Post는 보통 @RequestBody 를 이용해 값을 전달받습니다. @RequestBody, @RequestParam, @PathVariable 의 차이점을 살펴봅시다.

  • HTTP 메시지에 대해서 공부해봅시다.(여유가 된다면)

  • 경로를 매핑할 때, user/user를 혼용하여 쓰지말고, 하나로 통일해서 사용합시다.

2020-02-19 추가

  • instance의 field의 순서에도 신경을 써봅시다. or id값은 최상단에 위치하는게 JPA 컨벤션이랑 유사해서 그럴 수 있음.

    private String title;
    private String contents;
    private LocalDateTime createdDateTime;
    private int questionId;
    // 위 보단 아래가 더 좋습니다.
    private int questionId;
    private String title;
    private String contents;
    private LocalDateTime createdDateTime;
  • id 값은 toy Project가 아니라면 long형도 고민을 해봅시다.

  • 2String 같은 메소드명보다는 다른 메소드 명을 고민해봅시다.

  • DatetimeFormatter를 변수로 빼기보다는 한 번에 사용할 수 있다면 한 번에 사용해봅시다.

  • 여러 곳에서 사용하는 것이라면 static 메소드로 빼는 것도 고민해봅시다.

  • 자신만의 네이밍 컨벤션이어도 좋으니 고민해봅시다. https://www.slipp.net/questions/79

  • //UserController.java
    @ResponseStatus(HttpStatus.NOT_FOUND)
    static class UserNotFoundException extends RuntimeException {

    이런식으로 커스텀 익셉션을 만드는 것은 좋은데, 가급적이면 config 폴더에 custom Exception을 모아둡시다.

  •     {
            id = ++lastId;
            localDateTime = LocalDateTime.now();
        }

    code-squad/java-qna#132 (comment)

  • thread-safe한 collection을 사용한 것은 좋았습니다. ⇒ 이것에 대해서 좀 더 알아보세요.

  • if 문 안에서 break하기 보다는 return을 사용하는 방식을 고려해보세요.

  • code-squad/java-qna#132 (comment) 설정 추가에 관한 의견. (경험해보는 것은 나쁘지 않다.)

2020-02-21 추가

  • @RequestMapping 으로 중복 제거 👍 경로를 일치시켜주는게 중복이 제거되어 오류를 방지할 수 있습니다.
  • "/", "redirect:/" 의 차이 알기 (https://doublesprogramming.tistory.com/63)
  • 데이터 자료형은 String으로 가공해서 저장하기보다는 데이터를 출력할 때 가공해서 보여주세요.
  • 상수를 빼주는 것은 좋지만, 재사용성을 위해 Common Class로 빼는 것도 고려해보세요!
  • 테스트 하기 좋은 코드를 만드는 법: 객체 생성시 무조건 값이 채워지는 로직은 객체 내부에 선언하여 객체 생성시 값이 잘 들어왔는지 체크하기 좋게 합니다. ⇒ 단위테스트 하기 용이한 구조 만들기.
  • Restful한 Url은 리소스명을 복수로 적어줍시다.(https://meetup.toast.com/posts/92) 또한, 중복도 제거됩니다.
  • if break; 보다는 if return문을 사용해봅시다.
  • 찾는 자원이 없을 경우 어떻게 처리할지 생각해봅시다. code-squad/java-qna#135 (comment)
  • 불필요한 부분은 제거해줍시다.
  • 시간 관련 클래스는 Java 8 부터는 LocalDateTime, ZonedDateTime을 활용합시다.
  • 변수명을 좀 더 자세히 목적에 맞게 써줍시다.
  • 찾는 자원이 없는 경우에도 updateForm을 보여주면 어떻게 될까요? 빈 Form 화면을 보여주기보다 다른 처리를 해주는게 더 좋을 것 같습니다.
  • handlebars의 {{#each users}}{{users}}는 문법상 차이가 없습니다.
  • index라는 변수명은 색인이라는 뜻이 있기 때문에 id가 더 적절한 것 같습니다.
  • 템플릿 이름도 index보다는 main이나 welcome으로 바꾸어봅시다.
  • 불필요한 의존성, 설정은 없애줍시다. (왜 쓰는지를 알아야한다.)

2020-02-22 추가

STEP1

  • REST API의 경우에는 create 의 경우에 POST *s 형식으로 사용합니다.

  • stream API를 사용할 때, 각각의 메소드가 어떤 역할을 하는지 이해하고 사용합시다.

  • @RequestMapping 보다 @GetMapping, @PostMapping을 사용하는 이유: 보다 명확하기 때문에

  • setter에서는 값을 세팅만 하고, 다른 로직이 들어가지 않게하는게 좋을 것 같습니다.

  • field 정보 노출이 목적인 toString 메서드는 인텔리제이의 auto-generate 기능을 이용합시다.

  • 순회 후 해당하는 정보가 없는 경우는 NullPointerException이 아니라 RuntimeError를 그대로 throw해주어도 됩니다. https://cheese10yun.github.io/spring-guide-exception/

  • 메소드 순서에도 신경써주세요. (컨벤션)

  • 항상 같은 값을 제거한다면 다른 방법을 고민해보세요.

  • 하드코딩은 제거해주세요.

STEP2

  1. rest url, rest api, restful 등으로 관련 공부
  2. 객체지향 생활체조 연습 https://developerfarm.wordpress.com/2012/02/03/object_calisthenics_summary/
  • Entity의 getter, setter가 무조건 필요한 것은 아닙니다. JPA가 엔티티를 업데이트하는 방식은 필드접근, 프로퍼티 접근이(흔히 게터세터) 가 있는데요, 저도 찾아보니 @id어노테이션이 붙어있는 위치에 따라 디폴트 접근방식이 결정된다고 합니다. 보통 Long id. 즉 필드에 붙어있으므로 JPA는 엔티티를 수정할 때 필드 접근을 하기 때문에 setter는 따로 필요가 없고, getter도 핸들바에서 사용하는 용도가 아니면 비즈니스 로직에선 왠만하면 사용하지 않고 구현해보세요.
  • REST API에서 메소드의 역할에 따라 URL이 같아도 처리로직이 다르게 해줄 수 있음을 압시다.
  • @PathVariable 을 사용했을 때, PathVariable에 null 값이 들어오면 어떻게 될까요?
  • primitive typenull 값을 가질 수 없기 때문에, id값은 보통 long형이 아니라 Long형을 사용하는데 왜 그럴까요?
    • if (value == null) 과 같은 조건문을 작성하기 위해서 일 수도 있다.
  • Null 값이 들어오는 것을 잘 체크해야합니다. NullPointerException 처리도 잘 해주세요.
  • get, set 메소드 없이 user를 create하는 로직을 구현해보세요.
  • 용량이 큰 데이터는 JPA에서 @lob 어노테이션을 사용할 수도 있습니다.
  • 텍스트타입의 큰 데이터는 @type(type="text") 를 사용해 줄 수도 있습니다. Questioncontents 부분
  • 메소드 명을 좀 더 하는 행동이 명확하게 적어주세요.
  • QuestionwriterUser와 연관관계를 지어줄 수 있지않을까요?
  • JPA 쿼리 메서드 를 이용하면 @Query 어노테이션 없이 메서드 명 만으로 질의가 가능합니다.

내 리뷰

  • Common 이라는 클래스 명보다 좀 더 좋은 이름을 지어주세요.
  • 빈 블록은 한 줄에 써도 됩니다.
  • User 생성시 @RequestParam으로 직접 생성하는 것 대신에 User argument를 직접받는 방법도 생각해보세요.
  • DateTimeFormatter 자체를 static 변수로 선언하는 것은 어떨까요?
  • SQL 은 표준인 ANSI SQL을 기반으로 각 DBMS 벤더 별로 부가기능이나 특수기능, 커스텀 문법을 정의하는 dialect가 있습니다. JPA에서는 이 차이를 보정해주기 위해 유명 DBMS에 대해서 기본 구현체를 제공하고 있습니다. 이 설정으로 어떤 구현체를 사용할지 정하는 것입니다.
  • 인텔리제이 method extract 기능 사용시 주의할 점, Parameter에 선언된 Annotation이 같이 따라갈 수도 있다.
  • DB schema를 설계할 때, Non null 제약조건을 줄 때, 충분히 생각하고 모든 경우의 수를 파악해보는 것이 좋습니다. 복잡도 있는 구현을 할 때, 신경써주세요.

2020-02-24 추가

STEP1

  • gitignore 설정시 불필요한 파일 빼기
  • index라는 매핑은 정확히 말하면 색인 페이지에 사용해야 함.
  • RESTful에 대해서 공부하고 왜 url에 동사형이 사용되면 안되는지 고민하기
  • 불필요한 공백라인은 최대한 줄여주세요.
  • 코드 포맷팅에 신경써주세요.

STEP2

  • return template 명은 forward 해주는 것이 아니라 template을 지정해주는 것.
  • @Transient 어노테이션의 사용
  • 메소드에서 직접 에러를 처리해주는게 아니라, 다른 곳으로 redirect 시켜서 처리하도록 하는 것은 어떨까요?
  • 에러를 찍을 땐, System.err를 사용하는 것이 좋습니다. (더 좋은 것은 로그 구현체의 사용)
  • try-catch에서 아무처리도 안하는 catch는 안하는게 좋습니다.
  • 모델에 List를 직접 추가해주세요.

2020-02-25 추가

STEP2

  • 파라미터 없는 생성자에서 new 키워드로 객체를 생성하는 것은 자제해주세요.
  • 버전관리 되고 있는 소스를 통째로 주석처리 하지마세요. 주석은 코드에 대한 부가설명으로 사용하고, 코드 자체의 실행을 defer하는 용도로 사용하지 마세요.
  • Optional Type의 강제 언래핑은 지양하세요.
  • 같은 객체를 사용하는데 여러번 호출하지 마세요. (변수로 추출하기)
  • Wrapper Class를 사용할 필요가 없다면 primitive type을 사용해주세요.
  • JpaRepository와 CrudRepository의 차이점에 대해서 공부해보세요.
  • 부정 연산자의 괄호는 없는 편이 더 좋은 것 같습니다. 아니면 아예 부정연산자를 메소드 안에 포함시켜보세요. code-squad/java-qna#149 (comment)
  • 시간이나 화폐같은 정확도에 중점을 두어야하는 경우에는 잘 알려진 API를 사용해주세요.
  • HTTP, RESTful, 객체지향 프로그래밍에 관심을 두어보세요.
  • getter가 아닌 field명으로 직접 접근을 해주는 것도 방법입니다.
  • static final은 클래스 최상단에 위치시켜주세요.
  • 어떤 데이터에 연관된 비즈니스 로직은 그 데이터(password)를 가지고 있는 전문가(User)에게 요청을 보내는 편이 로직의 응집도를 높일 수 있습니다.
  • orElseThrow를 사용하지 않고 어떻게 조건문으로 처리할 수 있을까?
  • url을 정의할 때, 고민해보세요. (동사형 url이 나오면 보통 동작을 할 것이라고 예상하기 때문)
  • 객체가 null pointer일 경우 save 메소드를 수행하면 어떻게 될까요?
  • 예외를 사용해야할 경우
  • Exception과 RuntimeException의 차이
  • DB에 불필요하게 질의를 여러번하지 않게 하기
  • update 호출 시 예외처리 하는 방법의 장단점을 비교하고 어떤게 더 객체지향에 적합한지 고민해보기
    • update를 호출하는 외부 메소드 에서 question에 대한 null 체크
    • update 내부에서 question null 체크
  • getOne과 findById중 어떤것을 더 선호하나요? ⇒ findById가 Optional을 리턴해줘서 더 선호합니다.
  • setter는 변경하지 않는 편이 좋습니다. 다른 메소드를 만들어주세요.
  • 필요없는 주석은 제거해주세요.
  • 나중에 필요한 코드는 브랜치를 분리해서 수행하거나, tag를 붙여주는 것도 방법입니다.
  • 비밀번호 확인로직을 수행할 때, 그냥 user객체 자체를 넘겨주는 편이 더 선호됩니다. (객체간 의존도)
  • NullPointerException을 방지하는 코드 작성하기
  • boolean method의 네이밍은 is~가 더 선호됩니다.

2020-02-26 추가

Step2

  • Optional의 강제 언래핑을 지양해주세요. = .get() 메소드 지양하기

  • 로깅에 대해서 학습해야 할 점.

    • 로깅 레벨을 통한 로그 파일의 사이즈 통제
    • 환경별 로깅 파악을 다르게 함. (Develop 환경은 DEBUG, Production 에서는 INFO 이런식으로..?)
  • 엔티티 전체 범위에서 사용할 클래스 전역변수는 private static final 로 빼서 써도 됩니다.

  • 멤버 변수 선언시 신중할 것, private 만 붙이면 인스턴스 별로 달라질 수 있다는 의미 private static final 을 붙이면 클래스 상수를 의미함. 즉, 우리가 사용하는 변수에 대해서 접근 제어자 뿐만 아니라 제어자의 사용도 의미 있게 사용해야 함.

  • 핸들러 메소드 안에서의 문자열 연산도 성능 튜닝의 포인트가 됨

    TPS에 대한 얘기가 나와서... 검색. TPS에 대한 설명

  • 서버사이드 프로그래밍에서는 코드 한 라인 한 라인 증가할 때 마다 트래픽 증가에 따른 병목 포인트 및 사이드 이펙트를 고려하는 습관을 들이는 게 좋다. 클린 코드와 성능의 균형점을 잘 잡아야 함.

  • 스크립트를 직접 리턴해주는 것은 구식 방식 별도의 페이지를 주던지 XHR Response를 주어서 스크립트가 해석해서 동작을 취하는 방식으로 구현 크로스 사이트 스크립팅 취약점의 원인이 될 수 있음.

  • System.out.println() 을 사용하지말고 로깅을 사용할 것.

  • orElseThrow로 옵셔널 객체를 다룰 수 있음

  • crudRepository.save() 를 사용할 경우 반환값을 사용할 것을 권장(로깅 할 때)

  • assert 키워드는 개발단계에서만 사용할 수 있는 것으로 확신할 수 있는 로직엔 써도되지만, 예외처리에 이용하는것은 좋지않음.

  • update 로직을 객체를 직접 전달하는 방식으로 구현한 점👍

2020-02-27 추가

STEP2

  • 생성시간에 대한 네이밍 createdcreatedAt, createdTime
  • 기본 게터 세터는 유지하고, 새로운 메서드를 만들어서 사용하는 것을 권장
  • findById를 사용하면 Optional로 받아오므로 쿼리를 한 번만 날리면 되니까 성능상 Optional을 다루는 것을 권장
    • 유무를 확인한 점은 잘했음
  • 파라미터로 동일 클래스의 인스턴스가 들어왔을 때, 객체 필드에 직접 접근 가능함.
  • System.out.printlnlog.info() 와 같은식으로 로깅을 하는 것을 권장.
  • @RequestMapping(..., method = RequestMethod.PUT)@PutMapping(...)
  • Optional의 활용
    • if 절 flow를 다루는 것은 한 번 공부해 볼 만 한듯.
  • 패스워드 검사는 getter를 사용하지 않고 메서드를 만들어서 활용해보길 권장.
  • ModelAndViewModelView String을 따로 쓰는 방법의 차이는 ModelAndViewModel 이 필요없음에도 불구하고 가져야하는 단점이 있기 때문에 나중에 따로 쓰는 기법이 추가됨
  • redirect는 Client에 이 경로로 요청을 보내라는 것인데 GET 요청으로 오게됨.
  • HTTP 1.1 method의 용례를 알고 사용하기. 협업/커뮤니케이션에 도움이 됨.
  • 메서드 명은 되도록이면 동사로 지을 것
  • 비밀번호 비교는 User의 메소드로 사용하는 편이 좀 더 객체지향에 가까움

2020-02-28 추가

STEP2

  • 로그로 원인을 파악하는 것이 기본(잘했어요!)
  • 의존성 추가, 의존성 주입을 헷갈리면 안됨. (전혀 다른 얘기임)
  • user.getPassword().equals(password))user.matchPassword(password) 이렇게 비교하는 것은 어떨까요?
  • if 문을 중첩해서 사용하기 보다는 if return을 적극적으로 활용해서 indent를 줄일 수 있도록 노력해보세요!

내 리뷰(STEP3)

  • 전역 상수 클래스의 네이밍을 좀 더 생각해보세요. (2번째 지적당했음...)
  • DATE_TIME_FORMATTER ⇒ 어떤 DateTime을 Format하는지가 명확하지 않음.
  • URI는 언더바를 사용하지 않는것이 맞음 (왜그랬을까...) https://www.woorank.com/en/blog/underscores-in-urls-why-are-they-not-recommended
  • Annotation 때문에 읽기 복잡해지므로 Annotation이 있는 경우 한 줄씩 띄어주는게 좋음.
  • session.getAttribute를 바로 형변환해도 무방함.
  • equals 메소드 오버라이딩으로 비교하는게 너무 많음. JPA의 equals의 설계는 조심해야함. (id 값이 비교대상인가? ⇒ Entity의 생명주기 문제인듯.)
  • 요청을 주고받을 메소드의 결정은 프론트엔드에서 할 수 있도록 할 것.
  • equals로 부족하다면 다른 메소드를 작성해서 비교할 것
  • private 메소드들은 클래스 코드 가장 아래쪽으로 모을 것(클린코드?)
  • JPA Repository save 후 결과물을 return 해주는 것을 추천함. 관련 리뷰

2020-03-01 추가

STEP1

  • 포맷의 상수화는 재사용성을 고려해서 사용. (재사용률이 높지 않을 것이기 때문에 메소드에 있어도 괜찮을 듯!)
  • 메소드 네이밍을 명확하게
  • 변수 네이밍을 명확하게
  • Thread-Safe한 자료구조 사용하기
  • Thymeleaf 설정은 불필요하므로 제거할 것.
  • index보단 welcome으로 바꾸는게 어때요?
  • RESTful한 url로 만들기
  • @RequestParam 을 생략 가능한데, 사용할 때와 생략했을 때 동작의 차이가 있음. (한 번 알아보자.)

STEP2

  • 회원가입, 글 작성시 공백이나 빈 문자열 검사는 어디서 하나요? 답: 보통은 프론트에서 합니다.
  • 예외처리로 사용자 정의 뷰를 사용 ⇒ 해당 클래스가 지금 단계에서는 없는게 좋을 것 같습니다. 사용하려면 정확하게 사용하는 방법을 공부하고, view도 잘 만들어서 사용하는게 좋을 것 같습니다.
  • 로거를 사용할 때, info는 상당히 높은 레벨의 정보여서 debug를 사용하는 것을 추천합니다. 이에 관련되어 PR에 질문을 남겼었다.
  • 메소드 명을 명확하게 사용해주세요. CreateQnaCreateQuestion
  • getIndexlistQuestions
  • getQuestionshow
  • REST API ⇒ POST "/users" 면 유저 생성 url로 적당 /users/create 는 RESTful하지 않음.
  • 객체지향 isMatchPassword 는 User 객체가 들고 있는 것이 좋아보임. 객체는 스스로 행동한다!
  • HttpSessionUtils 클래스를 만든 것은 잘 했다... 이건 배울만한 부분.. @Component 를 붙이는 것을 고려해보는것도 좋을 것 같다는 리뷰. @Bean 과 @Component 어노테이션
  • 메소드 네이밍 session.isLoginUsersession.hasLoginUser
  • 기능단위별로 개행을 해서 가독성을 높여줍시다.
  • 문자열의 equals를 호출할 때에는 가능하면 null이 발생할 확률이 적은 쪽의 메소드를 먼저 호출해주세요. 사용자의 입력을 equals로 비교하기 보다는, 존재하는 데이터에 equals로 비교하는 것이 안전 문자열 상수와 문자열 변수를 비교할 때에는 무조건 상수쪽에서 equals를 호출하세요.
  • Optional에서는 .get() 보다는 .orElse(), .orElseThrow() 를 사용해주세요.
  • 변경하지 않고 사용할 거라면 final을 붙여주세요. DateTimeFormatter
  • 질: Controller의 repository는 공유해도 될 것이라고 생각하여 static으로 선언했는데 에러가 났습니다. 답: 스프링에서 @Repository, @Service, @Controller 와 같은 어노테이션을 달아주면, 별도의 Bean Scope를 지정하지 않으면 기본적으로 singleton 으로 정의됩니다. 매번 재 생성되는게 아니라 이미 Bean으로 만들어진 객체를 재사용하는 것이라서 static 으로 정의할 필요가 없습니다.
  • Error Controller를 만든 것. (별도의 다른 구현 없이 간단하게 처리할 수 있어서 이 방법도 괜찮은 것 같음)
  • WhiteLabelErrorPage가 어떤 동작을 통해 노출이 되는가?
  • Convention상 Entity Class에서 Id 값에는 long보다는 Long형을 사용해주세요.
  • User를 비교하는 메소드를 User에 정의해주어서 코드를 좀 더 깔끔하게 할 수 있을 것 같습니다. oldPassword가 기존 비밀번호인데, 맞는 naming인지 헷갈리네요.
  • user의 update 메소드 내에서 password를 비교하고 throw하는 것도 괜찮을 것 같습니다. code-squad/java-qna#166 (comment)

STEP3

  • 질: 리팩토링시 코드의 중복제거 말고 신경써야 할 부분이 있을까요? 답: 일단은 코드의 중복을 줄이는 것에 신경을 써주고, 리팩토링 도중에 에러가 나지 않도록 조심하세요.

  • 질: UserController에서 Update시 메소드명이 고민됩니다. update일까요? updateUser일까요? 답: update()가 좋습니다. User.update()가 자연스러우니까요.

  • 질: Answer는 Question에 종속이 된다고 생각하여 상속을 통해 해결하려고 하였지만 어렵습니다. 답: 종속이 아니라 관계를 가지고 있는 것입니다. 그래서 상속이 좋지 않습니다. 객체의 상속은 다른 이유로 이루어집니다. 나중에 나올거에요. (User - Question - Answer, User - Answer) 의 관계임 내 생각: 애초에 RDBMS라는 말의 의미가 관계형 데이터베이스 라는 말이므로, 상속보단 관계를 중심으로 생각하는게 맞는 것 같다.

  • 질: 로그인 상태를 알아보기 위해서 session을 이용한 방법 외에 다른 방법이 있을까요? 답: session을 사용하는 건 맞고, 더 좋은 방법이 있는데 그건 나중에 다룰 예정입니다.

  • model에 전달되는 data와 session으로 전달되는 data의 이름이 겹쳐선 안된다.

  • @Autowired 는 Springframework에게 해당 하는 클래스를 주입해달라고 하는 것, field Injection은 IDE에서 추천하지 않음... ⇒ 내 생각: 왜 일까?

  • HTTP가 무상태성인데 왜 쿠키랑 세션을 저장하지? ⇒ HTTP가 무상태성이기 때문에 쿠키와 세션이 필요한 것. HTTP에서 반드시 session이 필요하지는 않기 때문

  • 게터는 필드 클래스를 그대로 전달하는게 컨벤션임. 원하는 포맷으로 반환하고자 한다면 다른 메소드를 선언해서 반환할 것

  • static import를 하는 것을 고려해보기. (유틸성 메소드), 가독성에 어떤게 도움이 될 지 생각해보기

  • 엔티티 유무를 확인하는 것은 그 자체로 쿼리가 날아감, 따라서 엔티티 조회쿼리까지 총 두번의 쿼리가 날아가게 됨. findById를 적극적으로 사용하자.(Optional 이기 때문에 단 한 번의 쿼리로 검사와 조회까지 가능하다.)

  • NullPointerException 은 Catch하기 보다는 null 처리르 먼저 해주고 예외가 필요하다면 다른 것으로 바꾸는 것을 추천 NullPointerException 은 버그성이라서 catch를 해서 정상 flow를 타게 하기보다는 null 체크를 사전에 해야함. 내 생각: 회사에 있을 때, NullPointerException이 나면 전역 Handling을 해줬던 것 같다. (어찌됬든 에러페이지는 사용자에게 노출이 되면 안되므로.)

  • Exception을 문맥에 맞게 사용하기. Custom Exception을 만들어 처리하는 것은 어떨까요?

  • 객체의 연관관계를 맺기 시작할 때, 자동 작성되는 toString은 조심하기. (양방향 연관관계일 때 특히 조심) https://stackoverflow.com/questions/23973347/jpa-java-lang-stackoverflowerror-on-adding-tostring-method-in-entity-classes 대충 읽어본 결과 toString이 서로 계속 호출해서 메소드 call stack이 가득차서 stackoverflow가 발생하는 듯..

  • 메서드로 리팩토링 한 것(잘했다고 칭찬하셨음)

  • 생각해 볼 점 HashMap은 equals와 hashcode가 오버라이드 되어있어야 데이터를 넣고 지울 수 있는데, Repository의 Question Entity는 이 메소드가 없음에도 객체를 인식하고 지우는 이유는 무엇일까? 내 생각: id값이 Unique하기 때문에? 그리고 DB와도 연관이 있을 것 같다.

  • 객체 관계 매핑해보기

  • 중복이 발생하는 코드들은 중복제거를 해주기

  • 질: 로그레벨을 어떻게 주어야 하나요? 답: 코딩을 하다가 플로우를 잘 타는지 확인하는 용도 debug, info, warn은 어떤 목적이 있어 로그로 남겨야 할 때 사용 무분별한 로그는 좋지 않습니다. 호눅스 답: code-squad/java-qna#169 (comment)

  • NullPointerException을 throw하지 않기 ⇒ (버그성 코드임), 의미 있는 Exception을 발생시켜줍시다.

  • 로그를 남길 때 좀 더 의미있는 로그 남기기 (Login Failure) ⇒ (Login Failure. User is not existed. Id = '1')

  • 엔티티 조회결과는 Optional로 받아오기 (null 처리의 용이성)

2020-03-02 추가

STEP1

  • index의 의미에 대해서 생각해보기. 0으로 생성자에서 할당하는 이유는??
  • 의미 없는 setter 코드가 어떤 부작용을 가지고 오는지, 방어 코드를 어떻게 작성할 것인지(null 체크)
    • null이 발생할 상황을 항상 염두에 두는게 중요한 것 같다.
  • 객체지향적 설계(checkIndex 메소드는 question이 가지는게 맞지 않을까요?) 또한, 객체에 종속된 메소드가 외부에 위치한다면 코드가 전체적으로 달라져야 할 수도 있음. ⇒ 누락된다면, 에러발생 포인트가 될 수 있음.
  • REST api url 디자인

STEP2

  • @MappedSuperclass code-squad/java-qna#172 (comment)
  • dependency는 어디에 있는지 파악하고 그 저장소만 추가해주면 된다.
  • Lombok 도움 없이 프로그래밍 해볼 것(code-squad/java-qna#172 (comment))
  • @Query 어노테이션은 정확히 이해하고 꼭 필요할 때만 사용한다. code-squad/java-qna#172 (comment)
  • @Transactional이 필요한 상황
  • save를 수행했을 때 수행한 해당 객체를 그대로 리턴해주는 것이 안전하다. code-squad/java-qna#172 (comment)
  • 생성자로 바로 받기보다는, 다양한 경우를 위한 생성자를 protectedprivate 로 선언한 뒤에, static 메소드로 객체를 만들어주는 방식도 생각해보기.
  • @EnableJpaAuditing 이 없는데 잘 동작하나요..? -잘 모르겠음. code-squad/java-qna#172 (comment)
  • setter 개방하는 경우 왜 개방했는지 생각해보기. (id의 경우에는 아무런 제약없이 수정할 경우 중복키, pk 수정등의 문제가 발생가능)
  • url에는 복수형을 사용(Rest api url 디자인 원칙)
  • 최대한 생각할 수 있는 예외 상황에 대한 체크 및 처리 잘하기
  • 충돌 안나는 PR 보내기

STEP3

  • 메소드의 리턴값을 Optional 로 사용해보는 것을 추천
  • id 프로퍼티가 private가 아닌 이유는? 접근 제어자를 잘 할당합시다. 객체지향 - 캡슐화 관련 (누군가 내 정보(객체)를 변경할 수 없도록 방지 ) - null 체크도 포함
  • 게터/세터를 모두 선언해주지말자. 자주 나옴
  • 배열은 되도록이면 사용하지 말기.
  • 로그인 체크 → DB 조회하도록 하기 (불필요한 query가 안나가도록 하기) → 네트워크 응답 시간 감소하도록
  • null 처리 잘 하기

STEP4

  • Common 을 세부 클래스로 나눠보는 것도 추천합니다. 개수와 종류가 늘어날 경우 중복된 데이터가 생길 수도 있습니다.
  • Answer, Question에 setDeleted는 제거하기. (delete 메소드 처럼 의미있는 메소드로 원복을 하는 것을 생각해 볼 수도 있음.) - 부작용을 유발할 수 있는 코드.
  • Optional을 가져온다면, 조건문 처리를 할 수 있으므로, 굳이 예외를 발생시키지 않고 조건문으로 처리하는게 좋습니다. 아니면, 의도된 예외를 발생시켜 @ControllerAdvice@ExceptionHandler를 사용하여 일괄적인 예외처리를 해주는 편이 좋습니다.
  • getUserEmail().equals(user.userEmail)this.userEmail.equals(user.userEmail)
  • 변수명은 userEmail보다 email이 좋을 것 같음. (근데, 이걸 고치면 바꿔야 하는게 많아서 사이드 이펙트가 우려됨. 일단 보류)
  • try ~ catch 보다 Objects.isNull() 을 사용해서 조건문으로 처리해주는 것이 케이스마다 예외처리를 할 수 있음.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment