메가테라 22주차 주간회고 (프로젝트 6주차 회고)

 

22주 차 회고 (프로젝트 6주 차 회고)


메가 테라 22주 차를 진행하면서 있었던 일을 종합해서 회고하였습니다.

 

6주 차 작업 목표

6주 차의 목표를 세울 때 평소보다 더 타이트하게 잡았다. 그 이유는 디자인 주를 제외하고 프로젝트 마감까지 2주가 남았었는데 또 한 주는 관리자 페이지를 만들어야 했기 때문에 6주 차 동안에 사용자가 사용하는 기능은 모두 완성해야 했기 때문이다.

프로젝트 6주 차의 구체적인 작업 목표를 나열해봤다.

 

1. 마이 페이지(유저 정보 페이지)를 완성한다.

  • 자신의 정보를 확인하고 수정할 수 있다.(닉네임, 프로필 사진)
  • 마이 페이지에서 자신이 작성한 게시글, 댓글 수를 확인할 수 있다.
  • 자신이 작성한 게시글, 댓글을 삭제할 수 있다.
  • 자신이 좋아요를 누른 게시글을 확인 및 좋아요 취소 할 수 있다.

 

2. 게시글 검색 기능을 구현한다.

  • 게시글 제목, 내용, 작성자를 기준으로 

 

3. 서드파티 로그인 기능을 구현한다.

  • 카카오 계정으로 로그인할 수 있다.
  • 네이버 계정으로 로그인할 수 있다.

 

4. 회원가입 기능을 구현한다.

 

우선 계획했던 작업 목표는 네이버 로그인 기능을 구현하지 못해 100% 달성하지 못했지만 타이트하게 일정을 잡은 것 치고는 나름 선방했다고 생각한다. 카카오 로그인 구현을 하면서 async await 문제 때문에 시간을 많이 소비했었는데 이 문제를 더 일찍 해결했다면 네이버 로그인도 구현할 수 있지 않았을까 하는 아쉬움도 남는다.


6주 차 스토리 포인트 사용량은 아래와 같다.

 

마이 페이지

마이페이지를 구현하면서 했던 생각들이나 결과물에 대해 적어보려 한다.
가장 먼저 마이페이지를 구성할 때 필요한 정보들을 나열해봤다.
1. 사용자 닉네임, 프로필 사진
2. 작성한 게시글 수, 댓글 수
3. 사용자가 작성한 게시글 정보(제목, 작성자, 작성일, 조회수)
4. 사용자가 작성한 댓글 정보 (댓글 내용, 댓글 작성일),
5. 사용자가 좋아요를 누른 게시글 정보

마이 페이지에 접근했을 때 사용자 정보를 어떻게 가져올지 생각하다 사용자 페이지에 들어갔을 때 쿼리 스트링으로 얻어온 userId를 백엔드로 전달해 해당 유저의 정보 가져오는 방법을 생각했다. user의 고유 id로 해당 유저가 작성한 게시글, 댓글을 찾기 가능했기 때문이다. (게시글, 댓글 객체에 userId가 있기 때문)

그리고 마이 페이지에서 게시글 삭제나 프로필 수정같이 자신의 사용자 정보 페이지에 접근했을 때만 보이는 버튼을 어떻게 처리할지 고민하다 유저 정보를 요청할 때 요청하는 사용자의 accessToken을 header에 같이 담아서 요청해 백엔드 쪽에서 내 토큰인지 아닌지 검사해주는 방법을 생각했다.
그리고 만일 내 토큰 일시 User Entity의 필드에 isMyToken이라는 boolean 타입의 상태 값을 true로 바꿔 프론트 엔드에서 isMyToken이 true일 시 버튼이 보이도록 설정했다.
이때 isMyToken이라는 필드가 DB에 들어가면 안 되는 필드라고 아샬 님이 지적해주셨고 해당 필드가 DB에 안 들어가게 하는 방법으로 @Transient 어노테이션을 사용하면 된다는 것을 알게 되었다.

  • @Transient는 해당 데이터를 테이블의 컬럼과 매핑시키지 않는다.


위의 정보들을 종합해 REST API는 GET /users/{userId}로 사용자 정보를 요청한다. HTTP Headers에 자신의 정보를 요청하는지 다른 사용자의 정보를 요청하는지 인증을 위한 Access Token과 Body에는 정보를 확인하려는 사용자의 아이디 번호를 담아서 요청한다.

그런데 후에 이 방법이 완전 잘못되었다는 것을 알게 되었다. 마이페이지를 구현하는 동료 한분과 마이페이지의 url에 대해 이야기하다 방법의 차이가 있음을 인지하고 동료분이 질문을 남겼는데 아샬 님이 아래와 같은 코멘트를 남겨주셨다.

 

 

사용자의 id가 url에 노출이 된다는 건 뭔가 잘못되었다. 조금만 생각해봐도 userId가 모두가 볼 수 있는 url에 노출이 된다는 건 해킹을 당할 우려가 있는 부분이다.
그래서 마이페이지의 url은 기존에 사용했던 /users? id={userId}에서 /users/mypage로 수정이 필요하다.

 

구현한 마이페이지 화면

 

게시글 검색

게시글 검색 기능은 처음에 구현하려 했을 때 왠지는 모르겠는데 어려울 거라고 생각을 하고 있었다. 그래서 원래는 마이페이지 기능을 구현하고 하려 했지만 작업 순위를 맨 마지막으로 미뤘었는데 생각보다 게시글 검색 기능이 어렵지 않았다. JPA를 잘 활용하면 간단하게 구현할 수 있었다.
우선 게시판 검색 기능은 JPA의 Repository를 사용하면 메서드의 이름으로 쿼리를 지정해서 찾을 수 있다는 것을 알게 되었다.
SQL에서 LIKE연산자가 존재하는데 해당 연산자는 ‘~와 같다’라는 의미로 특정 문자열이 포함되어있는지 조회할 때 사용한다.
이 LIKE 연산자를 JPA Repository에서는 Containing으로 바꿔서 사용할 수 있다.

findByTitleContaining(keyword)

위와 같이 findBy이후에 어떤 칼럼에서 찾을지 칼럼명(Title)을 적어주고 Containing을 적어주면 해당 키워드를 찾아서 반환해준다.

 

위와 같은 모든 게시글이 있는 전체 게시판에서 어디서 찾을지 옵션(여기선 제목)을 선택하고 검색하면 제목에 피카추가 포함되어있는 게시물을 찾아와 준다.

 

검색한 게시물이 10개가 넘어갈 경우를 대비해 검색 결과에 대한 게시물에도 페이지네이션을 구현하는데 페이지 네이션이 제대로 되지 않는 문제도 만나 애좀 먹었지만 서비스단에서 문제 될만한 곳을 하나씩 결괏값을 출력해보면서 해결을 했다.
문제 상황과 해결방법은 TIL에 작성했었다. --> https://seungjjun.tistory.com/203

왜 못했는가?

지난주 회고할 때 이번 주에는 계획한 작업을 100% 달성하기로 회고했었는데 이번 주도 결국 100% 달성하지 못했다. 이번 주의 문제점을 짚어보자.
우선 가장 큰 문제는 처음 구현해보는 서드파티 로그인 기능에서 예상했던 시간보다 많이 사용했다는 것이다. 이전에도 채팅 기능을 구현할 때 처음 구현해보는 기능이고 공부해야 할 것들이 많아서 예상 스토리 포인트보다 훨씬 초과하여 구현할 수 있었는데 이번 서드파티 로그인도 비슷하다.

 

서드파티 로그인을 구현하면서 생각했던 대로 안 되는 부분이 많았고 그렇게 막힐 때마다 작업 속도가 현저히 느려지는 것을 인지할 수 있었다. 특히 카카오에서 보내준 인가 코드를 받아 백엔드에서 해당 코드를 통해 카카오 계정의 정보로 변환해 프론트엔드로 보내주는 것까지 성공했었는데 리액트에서 카카오 정보를 받는 과정에서 문제가 있었다.
카카오 정보를 요청하는 함수가 있는 페이지가 연속으로 두 번이 렌더링이 돼서 첫 번째 렌더링이 되었을 때 제대로 받아온 정보가 지워지고 한번 더 렌더링이 되어 만료된 코드를 받아 백엔드에 전달해 401 에러를 일으키는 것이었다 해당 문제는 usesffect안에 있는 카카오 정보를 요청하는 함수에 async await를 사용해줌으로써 해결할 수 있었다.
해당 문제를 해결하기 위해 주말에 4포인트 이상을 사용해도 해결이 되지 않아 작업 속도가 현저히 떨어졌던 것이었다.

문제를 만나 일정 시간 이상을 소비해도 문제가 해결되지 않았을 때는 작업 속도가 떨어지는 건 어쩔 수 없는 문제인 것 같다. 그러면 이 문제를 어떻게 해결할 수 있는지 방법을 생각해봤다.
우선 문제를 만났을 때 이 문제를 해결하기 위해 어느 정도의 스토리 포인트를 사용할 것인지 계획하고 계획한 스토리 포인트가 넘어갈 경우 문제 해결에 대한 힌트를 얻기 위해 질문을 하거나 동료들에게 문제 상황을 공유하는 것이다.
위에서 말한 카카오 문제도 동료에게 공유함으로써 해결했기 때문에 한정된 시간을 효율적으로 사용하기 위해서는 혼자 어느 정도 문제 해결을 위해 고민을 해보고 계획한 시간을 써도 해결이 되지 않는다면 빠르게 문제 상황을 공유하자.

이번 주 스크린 트은 기존에 기획한 관리자 페이지를 만드는 것인데 일주일의 시간밖에 없기 때문에 관리자의 핵심적인 기능을 잘 파악해서 작업 우선순위를 정하고 꼭 필요한 기능부터 구현하는 것을 목표로 하자!