2021-03-07-TIL

[CODE REVIEW] 미션1

  • Heroku에 처음 접속하면 꽤 긴 로딩시간이 발생합니다. 이를 어떻게 해결해줄 수 있을까요?

    • 로컬 환경에서는 저렇게까지 느리지 않은데, 처음 접속할 때만 느리네요. Heroku가 미국 서버인 것도 원인인 것 같은데, 해결 방법을 잘 모르겠습니다.. 다른 분들 중에 빠른 사람도 있고 아닌 사람도 있는데 좀 더 학습해보겠습니다!
    • 여러가지 조사를 해보니 서버 애플리케이션이 일정 시간동안 사용이 안되면 헤로쿠 서버의 메모리에서 자동으로 언로드 되는것 같습니다. 트래픽이 많을수록 서버의 메모리에 계속 상주하게 되는듯 합니다. 즉, 유독 빠른 서버의 경우 인기가 많은 서버일수도 있겠네요!
    • 같은 스터디원인 bat가 http://kaffeine.herokuapp.com 여기에 등록을 하면 30분 마다 ping을 날려서 서버를 데워주는(?) 방법을 알려주어서 등록해보았더니, 다소 빨라진 것 같습니다!
    • https://stackoverflow.com/questions/2606190/why-are-my-basic-heroku-apps-taking-two-seconds-to-load
    • https://www.quora.com/Scalability/Scalability-How-does-Heroku-work-2
    • https://devcenter.heroku.com/articles/how-heroku-works
  • https://august-qna.herokuapp.com/user/profile 여기로 접속하면 404가 발생하네요. 이건 어떻게 WhiteLabelErrorPage가 뜨는것을 해결할 수 있을까요?

    • 이 부분은 어떠한 해결사항을 말씀하지는지 이해가 잘 가지 않습니다. 기본적으로 회원가입 후 사용자 이름을 클릭하면, users/{userId}로 이동하여 프로필은 출력됩니다. 그리고 users/profile로 접속하면 현재는 이름이 비어있는 상태로 프로필 페이지가 표시됩니다. 하지만 비정상적인 url에 대한 처리를 해주어야 한다는 말씀이신가요?
    • https://goddaehee.tistory.com/214
    • https://zetcode.com/springboot/whitelabelerror/
    • https://techblogstation.com/spring-boot/whitelabel-error-page-spring-boot/
  • 회원정보 수정기능은 상식적으로 생각했을 때, 비밀번호가 채워져있으면 안되겠죠?

    • 사실, 그 생각은 했지만 비밀번호가 맞는지를 검증하는 로직을 구현하는 것을 다음 미션에서 수행하지 않을까 해서 일단 두었는데, 수정해야겠네요!! 😅
    • 우선은 updateForm.html에서 패스워드 부분을 제거했습니다. User의 update에서도 패스워드는 변경하지 못 하도록 했습니다. 패스워드 확인 후 변경완료를 하는 등의 로직은 미션을 좀 더 수행하고 해보겠습니다.
  • Controller의 책임이 너무 과도하게 많습니다. 적절하게 분리해주세요.
  • UserController::findUserById같은 로직은 Service에 포함되어야 한다는 것은 알겠습니다. 하지만 계속 시도해보았지만 의존주입과 같은 개념이 아직 많이 부족해서 이번 미션에서는 이 부분을 그냥 넘어가려고 합니다.. ;(
  • url 설정과 메서드 네이밍에 대해서도 좀 더 고민해봐주세요!
    • 같은 url을 가지더라도 메서드(GET, POST)로 식별이 가능해서 update로 변경했습니다!
  • System.out.println()은 이 미션 이후로 봉인해두시면 됩니다. Logger를 사용해주세요.

    • Logger의 필요성을 아직 느끼지 못해서 무작정 쓰기가 어려웠는데, 이참에 사용목적에 대하여 공부해보았습니다.
    • 로그를 보다 풍부하게 다루기 위해서 앞으로 Logger사용을 습관화해야겠습니다!
    • https://www.baeldung.com/java-system-out-println-vs-loggers
  • 여러 곳에서 접근할 수 있는 자원에 대해서 고민해봐주세요.
    • 이 부분은 멀티스레드 환경에서 synchronized되지않은 Collections에 대해서 말씀하시는 건가요? 지금은 이해가 부족해서 좀 보류하였습니다 ;(
  • 시간을 String 타입으로 저장하는 것은 어떤 손해가 있을까요?
    • 스프링에서는 기본적으로 String 파라미터를 Date나 다른 time 객체로 변환하는 것이 불가능하다고 합니다. 따라서 ConversionFailedException이 발생할 수 있습니다.
    • LocalDateTime을 저장하도록 변경했습니다!
    • https://www.baeldung.com/spring-date-parameters
registry.addViewController("/users/form").setViewName("user/form");
registry.addViewController("/users/login").setViewName("user/login");
registry.addViewController("/questions/form").setViewName("qna/form");
  • 이것이 어떤 설정인지 공부해보셨나요? 한 번 공부해봐주세요

    • ViewControllerRegistry

    상태 코드 and/or view로 미리 설정된 간단한 자동화 컨트롤러 등록을 지원합니다.

    • setOrder(int order)

    Spring MVC에서 설정된 다른 핸들러 맵핑과 관련된 뷰 컨트롤러를 맵핑 하는데 사용되는 HandlerMapping에 사용할 순서를 지정합니다 .

    • addViewController(String urlPathOrPattern)

    URL 경로 또는 패턴을 뷰 컨트롤러에 매핑하여 구성된 상태 코드 및 뷰로 응답을 렌더링합니다.

    https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/ViewControllerRegistry.html

  • codesquad-members-2021/java-chess#9 (comment) 여길 참고해서 설정 수정 꼭 해주세요~

    • https://blog.coderifleman.com/2015/04/04/text-files-end-with-a-newline/
    • https://johngrib.github.io/wiki/intellij/
@RequestMapping("/questions")
public class QuestionController {
    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private final List<Question> questions = new ArrayList<>();
  • 이름은 Controller인데, questions를 여기서 관리하는군요? 이렇게 개발하면 Controller의 책임이 많아지게 됩니다. 한 번 생각해봐주세요. 그리고, 여러 요청이 동시에 들어올 때 ArrayList는 과연 안전할까요?
    • https://www.baeldung.com/java-synchronized-collections
    • https://codeahoy.com/java/array-list/
    • service에 대해서 공부한 다음, service 패키지를 만들어서 별도의 서비스 클래스로 관리하도록 변경했습니다!
    • ArrayList 및 Collections의 기본 자료구조는 멀티스레드 환경에서 thread-safe하지 않습니다. 따라서 synchronizedList()를 사용하는 것이 바람직하다는 것을 공부했습니다.
    public String index(Model model) {
  • index보다 좋은 이름 고민해봐주세요 ㅋㅋ
    • https://dzone.com/articles/14-tips-for-writing-spring-mvc-controller
    • https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch16s10.html
    • 많은 자료를 찾아보았으나 기껏 찾은 것이 home이네요. 네이밍은 너무 어려운 것 같습니다. ;(
String formatDateTime = now.format(formatter);

question.setId(questions.size() + 1);
question.setCreatedDate(formatDateTime);
  • 흠.. 왜 포맷된 시간을 넣어주시는지 궁금하네요!
    • 저장할 때 String으로 저장하지 않게 되면 포맷된 시간을 저장할 필요도 없겠군요. 모델에 넘겨줄 때만 포맷을 지정하도록 했습니다.
private String createdDate;
  • 과연 시간을 이렇게 저장하는게 맞을까요?
    • 처음에 Date로 두었다가 html페이지로 부터의 전달이 쉽지않아서 이렇게 처리했었는데, LocalDateTime으로 저장하도록 변경했습니다.
    • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/format/annotation/DateTimeFormat.html
public String list(@PathVariable("id") long id, Model model) {
  • 메서드명은 list인데, list 아닌것 같네요.
    • show로 변경하고 index를 list로 변경했습니다.
  question.setId(questions.size() + 1);
  • 이 부분도 조심해야할 것 같아요. 여러곳에서 접근할 때를 항상 생각해봅시다.

  • 이제부턴 System.out.println()은 봉인하시고, Logger를 사용해주세요.

    • 네, Logger로 변경했습니다!

https://colorlib.com/wp/free-error-page-templates/


Template Engine

  • https://www.javaguides.net/2019/01/spring-boot-with-template-engines.html

Spring Boot project structure

  • https://medium.com/the-resonant-web/spring-boot-2-0-project-structure-and-best-practices-part-2-7137bdcba7d3
  • https://stackoverflow.com/questions/40902280/what-is-the-recommended-project-structure-for-spring-boot-rest-projects
  • https://www.javaguides.net/2019/01/standard-project-structure-for-spring-boot-projects.html
  • https://frontbackend.com/spring-boot/what-code-structure-use-for-spring-boot-applications