코딩과로그

1차 프로젝트 회고 (데브옵스 과정) 본문

회고록

1차 프로젝트 회고 (데브옵스 과정)

피리음 2023. 4. 5. 10:17

데브 옵스 부트캠프 1차 프로젝트로, [수강 신청] 에 대한 백엔드 API 설계 및 구현을 진행했다.

기능 요구사항은 아래와 같았다.

사용자는 모든 수업을 조회할 수 있다    
사용자는 특정 분류의 수업을 조회할 수 있다(강의자, 수업명, 수업코드 등)
사용자는 수업을 수강신청 할 수 있다    
사용자는 수업에 대한 수강신청을 취소 할 수 있다
사용자는 모든 수강중인 수업을 조회할 수 있다
사용자는 이메일 정보와 같은 개인정보를 변경할 수 있다
사용자의 타입이 강의자일 경우 새로운 수업을 생성할 수 있다

 

프로젝트 흐름은 다음과 같았다.

1. 요구사항 분석

2. ERD 작성

3. API 문서 제작

4. 코드 구현

5. 결과물 공유

 

그렇게 요구사항을 분석하였고,  더 이상의 요구사항은 없다는 가정하에, 확장성은 줄이더라도 최대한 테이블을 심플하게 가져감으로써 개발의 용이성을 가져가려 했고 3개의 테이블로 나눴다.

https://dbdiagram.io/d/642a23eb5758ac5f17262305

이후 API 문서를 만들었다. 스웨거를 사용했다면 좀 더 깔끔했을 것 같지만 우선 스크래치형태로 작성했었다.

수강 조회 관련 API 정의

이후 구현을 했다. 아래는 내가 구성한 강의 등록 함수이다.

  fastify.post("/", async function (request, reply) {
    try {
      // 강의명
      const { title } = request.body;
      // 인증을 위한 토큰값
      const { authorization } = request.headers;

      // 토큰 해석 리스트 (key: 토큰, value: '유저 table' 내의 id)
      const TokenKeyValue = {
        AAA: 1,
        BBB: 3,
      };

      // 토큰으로부터 user_id 얻어옴
      const user_id = TokenKeyValue[authorization];

      // 토큰 검증
      if (!user_id) {
        throw { statusCode: 403, message: "유효하지 않는 토큰입니다." };
      }
      if (title == undefined) {
        throw { statusCode: 401, message: "강의명이 없습니다." };
      }
      // 강의 추가 쿼리
      const insertQuery = ` INSERT INTO public.class (user_id, title) VALUES (${user_id}, '${title}');`;
      // 강사 찾기 쿼리
      const findProfessorQuery = `SELECT * FROM users WHERE users.is_professor = true AND users.id = ${user_id};`;
      // 추가한 강의 찾기 쿼리
      const findInsertedClassQuery = `SELECT * FROM class WHERE class.user_id = ${user_id} AND class.title = '${title}';`;
      const client = await fastify.pg.connect();
      try {
        const { rows: foundProfessors } = await client.query(
          findProfessorQuery
        );

        if (foundProfessors.length == 0) {
          throw {
            statusCode: 401,
            message: "강사가 아니여서 권한이 없습니다.",
          };
        }
        await client.query(insertQuery);
        const result = await client.query(findInsertedClassQuery);

        reply
          .code(200)
          .send({
            class_id: result.rows[0].id,
            message: "강의가 추가되었습니다.",
          });
      } finally {
        client.release();
      }
    } catch (e) {
      reply.code(e.statusCode || 500).send({ message: e.message });
      return;
    }
  });

일부 예외처리는 시간 관계상 진행하진 않았다. (강의 추가 중복 조건과 sql 서버 연동 실패시에 대한 예외처리 미진행함)

또한 토큰을 암화해 만드는 것과 해독하는 것은 이번 프로젝트에서는 진행하지 않았는데, 아무래도 데브옵스 과정이라 중요도가 크지 않을 것으로 보여 간략하게나마 흐름정도만 약식으로 구현했다.

 

느낀점

팀원들과 의사결정을 할 때는 언제가 쉽지 않다. 나는 프로젝트 의사결정 시에는 꽤나 고집이 많이 강한 편이라 내 뜻을 많이 어필하려하는 편이다.  특히 정답이 정해지지 않는 Trade-Off 관계의 의사결정일 경우 내 뜻대로 하고 싶은 부분이 겉으로도 드러나는 편이라 의사결정 과정에서 선택하는 게 어려웠었다. 이럴 때는 충분히 토의 후에도 과반수일 경우 과반수의 의견으로 가는 방향으로 진행을 하려했다. 1: 1로 의견이 나뉠 경우에는 사다리타기로 정하는 식으로 우선 진행했었다. 이런식으로 진행해야 일단 프로젝트가 빠르게 사이클을 돌 수 있으므로 괜찮은 방향인 것 같다. 토론과정에서 trade-off 에 관해서 고민을 해왔으니 프로젝트 진행과정에서 논의 했던 점을 신경을 더 쓸 수 있어서 좋은 토론이 되는 것 같다. 

 

프로젝트 업무 자체로만 본다면 백엔드를 해봤던 입장에서 크게 어렵지 않았다. 다만 이전에는 express 노드로 백엔드 개발을 해왔었는데 이번 데브옵스 부트캠프를 통해서 처음으로 fastify 로 개발을 해봤다 (express가 그리워졌다.). 익숙하지 않아서 좀 불편했고 fastify를 간략하게만 본 입장에서 라우팅을 정의하는 방식이 express가 더 직관적이고 편리했다. 

 

이번 백엔드 프로젝트를 기반으로 이후 프로젝트에서는 도커 등을 통해 배포하는 작업을 진행할 것으로 예상되고 기대된다 ~!