Today I Learned
-
밀린다Today I Learned 2022. 11. 17. 23:07
게시글 상세 정보 조회를 위한 로직을 이틀에 걸쳐 구현을 진행 중이다. 특정 게시글이 포함하고 있는 게시물 내용, 경기 정보, 참가자 목록 정보를 백엔드 서버로부터 가져와 사용자, 신청자, 신청자가 아닌 사용자에 따라 UI를 구분해 출력되도록 하는 것이 작업의 최종 목표이다. 월요일에 작업 목록을 새로 작성할 때, 작업이 너무 클 것 같아 작업 단위를 나눴었다. 먼저 게시글을 구성하는 각각의 리소스인 '게시글', '경기', '참가자'에 대한 내용을 일단 가져와 출력하기만 하게 구현한 뒤, DTO에 추가적으로 같이 전달하게 하는 사용자 식별을 위한 값을 이용해 컴포넌트가 출력할 내용을 구분하는 내용을 구현할 계획이었다. 남은 일정과 작업 목록을 고려한다면 오늘이 끝날 때쯤에는 적어도 리소스를 출력하는 로직..
-
@RequestBody에 매핑되는 DTO는 왜 빈(empty) 생성자가 필요한가?Today I Learned 2022. 11. 16. 13:24
임시 로그인을 구현하기 위해 백엔드 로직을 작성하던 중 한 가지 난관에 봉착했다. LoginRequestDto를 받아와 처리하는 Controller의 동작을 정의하기 위해 테스트 코드를 작성하던 중, @RequestBody에 매핑된 LoginRequestDto를 생성할 수 없다는 에러 메세지가 출력되면서 테스트가 실패하는 것을 확인했다. // SessionController.java @RestController @RequestMapping("session") public class SessionController { // Beans, Constructors @PostMapping @ResponseStatus(HttpStatus.CREATED) public LoginResultDto login( @Vali..
-
인수 테스트는 개발자가 아닌 사람들도 이해할 수 있어야 한다Today I Learned 2022. 11. 15. 14:33
문서에 작성했던 인수 테스트의 내용을 소스코드로 옮긴 테스트 코드가 통과하지 못하고 있었다. 실 사용 화면에서는 DB에 있는 데이터들을 잘 가져오고 있었는데, CodeceptJS로 테스트를 실행하면 계속해서 상태를 가져오지 못하는 것을 확인했다. 처음에는 실행 순서상으로 페이지가 렌더링되고 상태를 가져오기까지 잠깐 동안 출력될 수 있는 Guard Clause로 인해 테스트를 통과하지 못하는 것인가 싶어 페이지 이동 후 대기하게 하는 식으로 수정해보았지만 여전히 게시물을 가져오지 않았다. 동료분과 인수 테스트의 어느 지점에서 막히고 있는지 과정을 하나씩 살펴보았다. // tests/posts_test.js Scenario('동록된 게시글이 존재하는 경우', ({ I }) => { // Given I.set..
-
테스트를 짤 때 느껴지는 이상함은 구조 분리의 신호Today I Learned 2022. 11. 14. 06:33
어제 사용자가 신청하지 않은 운동 게시글에 운동을 신청했을 때, 예외가 발생할 경우 예외 메세지를 출력하게 해주는 로직의 UI 컴포넌트 부분과 테스트 코드를 작성하는 과정에서 겪었던 이슈가 있었다. 아래의 소스코드와 테스트 코드를 보자. // src/components/Posts.jsx import styled from 'styled-components'; // Definitions of styled components // ... export default function Posts({ posts, postsErrorMessage, registerErrorCodeAndMessage, registerToGame, cancelRegisterGame, }) { const handleRegisterToGame..
-
Flux 구조에서의 상태 관리 책임의 분리Today I Learned 2022. 11. 12. 22:32
엊그제 운동 참가 신청 최소 기능을 구현하는 과정에서 고민했던 부분이 있었다. 신청 버튼을 누르면 API 서버에 POST 요청을 보내고, 응답으로 신청된 경기의 식별자가 있으면 게시물 목록을 다시 가져오게 하려고 했다. 상태 하나를 저장하기 위해 굳이 Store까지 만들어야 할까 생각이 들어 페이지 컴포넌트가 바로 API 요청을 호출하면 안 되는지 질문을 올렸다. 또 한번 강의에서 배우지 않은 내용대로 하려고 했음을 인지하고 Store에서 API를 호출하고, 응답으로 돌아온 신청된 경기의 식별자를 Store에 저장한 뒤 페이지 컴포넌트에서는 Custom hook으로 Store가 들고 있는 상태에 접근하도록 했다. 물론 비동기 처리만 해 주면 페이지 컴포넌트가 API를 바로 호출하게 해도 문제는 없다. 그..
-
인터페이스는 내가 쓰기 편해야 한다Today I Learned 2022. 11. 12. 22:31
어제 완성했던 최소 기능의 게시글 목록 조회, 신청 기능을 테스트하는 테스트 코드에 한 가지 문제가 남아있었다. 테스트 코드에서 사용될 인스턴스들을 만들기 위해 사용하는 fake 메서드만을 봐서는 post나 game, member에 대체 어떤 값을 줘서 fake 인스턴스를 만드려는 건지 알 수 없었다. 그래서 오늘 가장 먼저 수행할 작업으로 객체들이 가진 식별자와 필드를 값 객체로 분리시키는 작업을 계획했다. 필드를 값 객체로 분리시키는 작업은 값 객체로 분리시킬 객체를 @Embeddable 어노테이션이 붙은 객체로 분리하고, 객체 내에서 쓰일 값 객체에 @Embedded 어노테이션을 붙이는 것으로 분리할 수 있었지만, 식별자 필드를 값 객체로 분리시키는 것은 써본 적이 없었기 때문에 값 객체를 쓰는 식..
-
핵심 가치에 집중하니 크기는 줄어도 내용은 견고해졌다Today I Learned 2022. 11. 11. 23:51
20주차 금요일 성수 코딩 도장 일과를 진행하면서 느꼈던 점을 정리했다. 오늘의 최소 기능 구현: 참가 신청하기 오늘은 게시물 리스트를 보고 사용자가 신청 버튼을 누를 경우 참가자 수가 증가하고, 버튼이 신청취소로 바뀌는 기능을 구현했다. 이전에 작성했던 화면과 작업 계획은 잠시 내려놓고, 핵심 가치에 집중해서 기능을 설계하고 구현을 진행하면서 느낀 점이 몇 가지 있다. 소스코드는 설계를 보면서 작성하고 있다 지난 주까지는 소스코드를 작성할 때 작업 Task 목록에서 잠깐 구현 방식을 고민한 다음에 소스코드를 작성했는데, 중간중간 멈칫할 때가 많았다. 기능 자체가 너무 크다는 점과 시너지를 일으키면서 인지 부하가 계속해서 일어났다. 반면 설계 문서에서 작성한 API의 내용을 보면서 구현을 진행했을 때는 ..
-
최소한의 기능으로 다시 시작하기Today I Learned 2022. 11. 10. 10:54
어제 저녁, 게시글 목록을 불러오는 프로세스를 리팩터링하고 있었다. 게시물 썸네일 하나를 구성하는 여러 리소스의 내용들을 프론트엔드에서 리소스 각각에 맞는 API를 호출해 내용을 따로따로 가져오고, UI 컴포넌트에서 출력하기 전 각자의 게시물에 맞는 내용으로 조합시키려 했다. 아래와 같이 게시물, 이미지, 운동 경기, 운동 장소, 포지션에 해당되는 리소스를 호출하는 API를 불러오는 페이지 컴포넌트가 만들어졌다. xport default function PostsPage() { const postStore = usePostStore(); useEffect(() => { postStore.fetchPosts(); postStore.fetchImages(); postStore.fetchGames(); pos..