API를 구현하고 여러 추가적인 코딩스타일, 컨벤션을 확립하기 시작했다.

유저가 자신이 신청한 웨이팅 목록을 확인하는 API

@ApiTags('Waiting')
@Controller('waiting')
export class WaitingController {
  constructor(private readonly waitingService: WaitingService) {}

  @Get('/list')
  @ApiOperation({
    summary: '유저가 자신이 신청한 웨이팅 목록을 확인하는 API',
  })
  @ApiQuery({
    name: 'phoneNumber',
    description: '웨이팅 목록을 볼 유저의 전화번호',
    type: 'string',
  })
  @ApiResponse({
    status: 200,
    description: '웨이팅을 신청한 부스들의 정보 배열',
  })
  @ApiResponse({
    status: 404,
    description: '조회하려고 하는 유저의 웨이팅한 부스가 없습니다.',
  })
  async getWaitingStatusList(@Query('phoneNumber') phoneNumber: string): Promise<WaitingStatusType[]> {
    return await this.waitingService.getWaitingStatusList(phoneNumber);
  }
}

우리는 전에 설정했던 swagger를 모든 api에 대하여 같은 format으로 정보를 표시할 수 있게 swagger 정보를 적는 순서를 위와 같이 적기로 정했다. 그리고 response 정보의 경우에도 ApiOkResponse와 같이 이미 만들어져있는 데코레이터를 이용하는 것이 아니라 ApiResponse로 통일하고 성공/실패 순으로 직접 직관적으로 표현하기로 했다.

async getWaitingStatusList(phoneNumber: string): Promise<WaitingStatusType[]> {
    try {
      // 오늘 날짜의 waiting 기록만을 가져오기 위해서 오늘 날짜를 정확하게 계산합니다.

      // 현재 시간을 가져옵니다.
      const today = new Date();

      // UTC 기준의 타임스탬프를 계산합니다.
      const utcTimestamp = Date.UTC(
        today.getUTCFullYear(),
        today.getUTCMonth(),
        today.getUTCDate(),
        today.getUTCHours(),
        today.getUTCMinutes(),
        today.getUTCSeconds(),
        today.getUTCMilliseconds(),
      );

      // 한국 타임존과의 시간 차이를 계산합니다.
      const krTimeDiff = 9 * 60 * 60 * 1000; // 9시간

      // 한국 타임존의 타임스탬프를 계산합니다.
      const krTimestamp = utcTimestamp + krTimeDiff;

      // 타임스탬프를 사용하여 새로운 Date 객체를 생성합니다.
      const krCurr = new Date(krTimestamp);

      // 날짜만 필요하기에 시간 정보는 0으로 초기화합니다.
      krCurr.setUTCHours(0);
      krCurr.setUTCMinutes(0);
      krCurr.setUTCSeconds(0);
      krCurr.setUTCMilliseconds(0);

      // 유저가 waiting을 신청할 수 있는 부스는 최대 3개까지 있으니, 
			// 해당 부스들을 데이터베이스에서 가져옵니다.
      const userWaitingInfo: Waiting[] = await this.waitingRepository.find({
        relations: {
          booth: true,
        },
        select: {
          id: true,
          createdAt: true,
          booth: {
            id: true,
            name: true,
          },
        },
        where: {
          phoneNum: phoneNumber,
          status: '대기중',
          createdAt: MoreThan(krCurr),
        },
      });
      const res: WaitingStatusType[] = [];

      // 유저가 waiting을 신청한 부스에 waiting 목록 중,
      // 자신 보다 앞 팀이 몇 팀 있는지 계산하고 부스 관련 정보와 함게 전달합니다.
      for (const obj of userWaitingInfo) {
        const waitingCntList: Waiting[] = await this.waitingRepository.find({
          relations: {
            booth: true,
          },
          select: {
            id: true,
            createdAt: true,
            booth: {},
          },
          where: {
            booth: {
              id: obj.booth.id,
            },
            createdAt: Between(krCurr, obj.createdAt),
            status: '대기중',
          },
        });

        const temp: WaitingStatusType = {
          boothName: obj.booth.name,
          createdAt: obj.createdAt,
          rank: waitingCntList.length - 1, 
					// 1을 빼는 이유는 between 연산을 하면 자기 자신도 가져오기 때문입니다.
          waitingId: obj.id,
        };

        res.push(temp);
      }

      return res;
    } catch (e) {
      throw new NotFoundException(`${phoneNumber} does not exist.`);
    }
  }
}

그리고 개인적으로 지금부터 주석을 달기로 했다. 주석을 달아두면 코드 리딩도 확실해 쉬어지고 내가 나중에 내 코드를 수정할 때에도 편리하기 때문이다.

위의 코드가 하는 일은 다음과 같다.

  1. 유저의 전화번호를 이용해서 유저가 waiting을 신청한 정보를 가져온다. 한 유저는 최대 3개의 부스에 waiting을 신청할 수 있으므로 배열로 가져온다.
  2. 웨이팅을 신청한 부스 별로 나보다 앞에 있는 웨이팅 팀 수를 계산해서 부스 정보와 함께 제공한다.

이것을 하려다가 내가 맞이한 문제는 2가지가 있었다. 첫째는 createdAt이라는 변수에 주어야 하는 조건이 “오늘 날짜 이면서” “나보다 예약시각이 빠른” 이렇게 2가지 였는데, find문을 사용해서는 한 칼럼에 두 조건을 다는 것이 어려웠다. 그래서 찾아보니 querybuilder를 사용해서 where 와 andwhere를 사용해야한다는 것을 깨닫았는데, 아직 querybuilder에 대한 공부가 부족해서 find만을 이용해 구현하기 위하여 between 메소드를 사용하기로 했다. 이를 위해 오늘 날짜를 정확하게 연산할 필요가 있었고 모든 환경에서 항상 한국의 표준시각을 알려주기 위해 앞에서 미리 연산을 진행했다.

왠지 모르게 내 컴퓨터 자체 시각은 분면 한국표준시로 맞추어져 있는데 자바스크립트에서 생성해주는 현재 시각 객체는 지금 시각으로 나오지 않았었다. getTime을 이용해 시간을 가져와봤지만 그 연산 결과도 자바스크립트에서 알려주는 시각과 같았다. 공부를 조금 진행해본 결과 UTC 함수로 처리를 해주지 않아서 인 것 같았고 그래서 이를 처리해주었다.

원래 for문을 c++에서 사용하는 것 처럼 사용했었는데 for of문과 같은 문법이 따로 있다는 것을 배워 새롭게 적용해보았다.

내 코드에 대한 피드백으로는 waiting을 신청한 부스마다 db를 한 번 씩 접근하고 있는데, 굳이 이렇게 하지 않고 한 번의 db 접근으로 배열을 최대 3개까지 받아 오는 방식이 가능할 것 같다는 이야기가 있었다. orderby를 이용하면 된다는데 아직 공부가 부족한 것 같다. 물론 3번밖에 연산하지 않아 크게 손해가 되는 연산은 아니지만 추후에 고칠 수 있다면 꼭 고쳐보고 싶다.

의존성 주입에 관한 토론

전체적인 코드 리펙토링 과정에서 우리는 url의 통일성을 가져가기 위하여 컨트롤러 부분을 다른 모듈과 병합하는 과정을 진행했고 그 결과 컨트롤러는 모듈 A에 있는데 서비스는 모듈 B에 있는 상황이 발생했다. 우리는 이를 해결하기 위하여 전에 사용했던 controller에 service를 주입하는 방식으로 진행을 하려고 했는데, 찾아보니 controller에 주입하는 방법 뿐만 아니라 service끼리 서로 주입을 하는 방법도 있어서 우리는 서로의 장단점에 대하여 고민을 해보았다. controller에 주입을 하면 원치 않는 business logic이 controller 코드 안에 발생할 수 있고 이는 코드 디자인에서 그닥 좋은 선택지는 아니라는 의견이 나왔다. 우리는 일반적인 현업에서 사용하는 방식을 알아보고 싶어 구글링을 해보았지만 적절한 예시를 찾지 못했고, 토론의 결과는 우리의 서비스에서 컨트롤러에 복잡한 비즈니스 로직이 들어가지 않을 것 같다는 예측과 함께 controller에 service를 주입하는 방식으로 일단 진행하고, 추후에 이 방식에 문제가 생기면 리펙토링 하는 것으로 마무리 지었다.