회고#1. NewsFeed 프로젝트

깡통·2024년 2월 15일
0

<준비>
1.API 명세

  • API 명세를 작성하는데 의외로 시간이 많이 걸렸던 것 같다.
  • 17 개 정도의 API 명세를 작성하고 시작했다. 이 정도면 충분(어쩌면 과하다고도)하다고 생각했지만, 실제로 프로젝트를 진행해보니
  • API 명세서에 적히지 않는 것들이 꽤 있었다. 예를 들면, 미들웨어라던지, 컨트롤러 같은 것들(우리 프로젝트는 PASSPORT를 사용하기 위해 마지막에 로그인 컨트롤러가 적용됐다).
    • API 명세서는 어떤 기능을 가진 API를 사용하겠다라고 알려주는 문서라고 한다. 굳이 어떻게 구축하겠다는 내용을 쓸 필요는 없는 것
    • 그래서 미들웨어, 컨트롤러까지 굳이 작성할 필요는 없다(다만 이걸 기능에서 활용하겠다라고 작성하는 건 괜찮음)
  • API는 변경 사항이 있을 때마다 업데이트 하는 것이 원칙이라고 한다.
  1. ERD
  • DB스키마를 어떻게 조직해야 할지 결정하기 위해 작성하는 DB 테이블 구조도라고 할 수 있다.
  • 얘도 처음에는 4테이블 정도(Users, refreshToken, Posts, Comments) 작성하면 될 줄 알았는데, 하다보니 Follow, Likes 등등 여러 테이블이 더 필요해져서 작성하게 됐고, 테이블 내 컬럼도 점점 추가됐었다.
  • 이런 일이 있을 때 마다 ERD를 수정해야 한다고 한다. 다음 프로젝트 때는 꼭 변경사항을 꼼꼼히 기록해서 트래킹 해야겠다.
  1. 의존성
  • 처음에 시작할 때 필요한 의존성을 꼼꼼히 고려하지 못했다.
  • 그래서 팀원들 사이에 의존성 차이가 많이 발생하였고, 서로 섣불리 깃을 받기 어려운 상황이 발생하였다.(git confilit가 많이 발생하였음)
    • 그래서 내가 중간에 필수와 선택 과제를 끝낸 직후 코드만 취합해서 최신화 한 후 깃에 새로운 브랜치를 파는 형태로 작업을 했는데, 이렇게 하면 깃 커밋 히스토리도 제대로 남지 않을 뿐더러 만약 취합 과정에서 내가 큰 실수를 저질러 내 자료가 쓸 수 없는 상황이 됐다면 많이 힘든 상황이 발생했을 것이다.
  • 그래서 다음에는 처음에 시간이 걸리더라도 팀원들과 충분한 회의를 하며 필요한 의존성을 합의하는 과정을 거쳐야 겠다고 생각했다.

사전 준비를 하는 과정에서 가장 많이 반성하는 것은 충분한 대화를 하지 않고 실제 프로젝트에 투입했다는 것이다.
충분한 대화를 하지 않으면 프로젝트에 대한 공감대가 형성되지 않고, 결과적으로 싱크가 맞지 않게 되는 것 같다.
다음 프로젝트에서는 충분한 대화를 거쳐 공감대를 형성한 후에 프로젝트를 시작해야겠다.

<프로젝트 중>
1. 나는 1시간 ~ 3시간 정도 단위로 계속해서 팀원들의 진행 상황을 점검하였다. 필요한 점, 어려운 점, 원하는 점을 지속적으로 체크하며 이에 맞추어 유동적으로 업무 분장을 바꾸며 프로젝트를 진행하였다. 나쁘지 않은 방식이었다고 생각한다.

  1. 팀원들이 최대한 서로 눈치보지 않고 자유롭게 원하는 바를 말할 수 있는 분위기를 만들고자 노력했다. 나는 개인적으로 최소한 업무적으로는 서로 눈치보면서 해야할 말과 하고 싶은 말을 할 수 있어야 한다고 생각하기 때문이다(비난과 비판은 제외, 얘네는 공격의 개념이 포함되어 있어서 어쩔 수 없이 사람의 감정을 상하게 하고 심하면 팀워크 자체를 왜하시킬 수 있기 때문에 이걸 자유롭게 말할 수 있는 분위기를 만들려면 매우 신중하게 접근해야 한다고 생각한다). 그래서 팀원들이 자유롭게 자신이 원하는 바를 말할 수 있었던 것 같긴 하다. 다만, 그게 그들에게 어떤 느낌이었는지는 잘 모르겠다. 가능하다면 피드백을 한 번 받아보고 싶긴 하다.

그래서 결론을 말하자면 좋은 팀이었다고 생각한다. 소통에 막힘이 없었기 때문에 우리의 의사결정은 항상 빨랐고, 아무리 늦어도 10분 안에 결정됐다. 프로젝트 진행 중에는 모두가 각자의 자원을 최대한 활용했고, 최선을 다했다. 그래서 명예의 전당 같은 아직 생소하고 어려운 개념을 시도했음에도 불구하고 우리는 유의미한 결과를 낼 수 있었다.
만약 이들과 또다시 이 팀을 해야 한다 해도, 난 좋다고 생각한다.

<코드 리뷰>

  • 내가 프로젝트를 진행하면서 처음 봤거나, 혹은 인상적이어서 꼭 기억해두고 싶은 코드를 작성하고자 한다.
    아마 미래에 도움이 되는 날이 있겠지.
    • const s3 는 aws s3에 저장하기 위해 저장소를 특정하는 로직이다.(aws-sdk 모듈이 필요하다)
    • 'const storage' 부분은 저장되는 파일의 이름을 지정하는 로직이다.
    • 'const upload' 부분은 파일의 양식을 정하는 로직이다.

<좋아요>

  • 이 비즈니스 로직에서 내가 기억하고 싶은 건, 삭제를 하기 위해 굳이 HTTP delete 요청을 보낼 필요는 없다는 것이다. 어떤 요청 형식으로 보내건 간에, 비즈니스 로직 안에 삭제 로직만 있으면, 요청이 성공적으로 들어가면 삭제도 된다. 꼭 router.delete에 목맬 필요 없다.
``` import nodemailer from "nodemailer"; import { createEmailToken } from "./token.js"; import "dotenv/config";

const transporter = nodemailer.createTransport({
service: "Naver",
host: "smtp.naver.com",
port: 587,
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,
},
});

const emailTemplate = (code) => {
const site = {
name: "TravAll",
validUrl: http://localhost:${process.env.PORT}/api/emailValid?code=${code},
};

return `

${site.name}이메일 인증

${site.name} 이메일 인증

안녕하세요

${site.name}에 가입해 주셔서 감사합니다!

계정을 활성화하려면 아래 버튼을 클릭하여 이메일 주소를 인증해 주세요.

만약 버튼이 작동하지 않는다면, 아래 링크를 복사하여 주소창에 붙여넣고 엔터를 눌러 주세요.

${site.validUrl}

`; };

export const emailCodeTransporter = (code, email) => {
const mailOptions = {
from: process.env.EMAIL_USER, // 발신자
to: email, // 수신자
subject: "TravAll 인증 코드 발송", // 제목
html: emailTemplate(code), // 본문
};
transporter.sendMail(mailOptions, (err, info) => {
if (err) {
console.log(err);
} else {
console.log("Email sent: " + info.response);
}
});
};

  • 비즈니스 로직이 어떻게 흐르는 지 대략적으로 알겠는데, 구체적으로 정확히 와닿지는 않는다. 이건 다음에 쓸 일이 있을 때 써보고자 한다.

<refreshToken/accessToken>

import jwt from "jsonwebtoken";
import { prisma } from "../utils/prisma/index.js";
import "dotenv/config"

const { TOKEN_SECRET_KEY } = process.env;

export const createEmailToken = (userData) => {
  return jwt.sign(userData, TOKEN_SECRET_KEY, {
    expiresIn: "1h"
  })
}

/**
 * @param {Object} userData
 * @returns {String}
 */
export const createAccessToken = (userData) => {
  return jwt.sign(userData, TOKEN_SECRET_KEY, {
    expiresIn: "12h",
  });
};

/**
 * @param {String} token
 * @returns {Object}
 */
export const verifyToken = (token) => {
  try {
    return jwt.verify(token, TOKEN_SECRET_KEY);
  } catch (err) {
    throw err;
  }
};

/**
 * @param {Object} userData
 * @returns {String}
 */
export const createRefreshToken = (userData) => {
  return jwt.sign(userData, TOKEN_SECRET_KEY, {
    expiresIn: "2d",
  });
};

export const generateTokens = async (res, userData) => {
  const accessToken = createAccessToken(userData);
  const refreshToken = createRefreshToken(userData);
  res.cookie("accessToken", accessToken);
  res.cookie("refreshToken", refreshToken);

  const user = await prisma.refreshToken.findFirst({
    where: {
      userId: userData.userId,
    },
  });

  if (user) {
    await prisma.refreshToken.update({
      where: {
        userId: userData.userId,
      },
      data: {
        refreshToken,
      },
    });
  }else{
    await prisma.refreshToken.create({
        data:{
            userId: userData.userId,
            refreshToken
        }
    })
  }

  return { accessToken, refreshToken };
};

  • 골뱅이들은 어떤 의미를 가진 걸까?

<-ejs->

  • <%- -%> 는 서버사이드 렌더링 데이터이다. 받아서 요긴하게 사용할 수 있다.(핸들바라는게 있다는데 이거보다 좋은 거라고 한다. 다음 프로젝트때 써봐야지)

  • fetch를 통해서 통신할 때는 JSON 데이터형 자료의 경우 문자열로 바꿔서 보내야 한다.(그게 fetch의 작동 방식이다)

  • 참고로 fetch는 인섬니아라고 생각하면 편하다. fetch(url, options)는 인섬니아 본체, url은 fetch에서 경로 적는 곳, options는 req body, headers 등이다.

  • 여기서 보이는 것 처럼, fetch등의 함수를 통해 라우터를 호출하는 것이 가장 안정적이고 좋다. 프론트와 서버를 연결할 땐 가급적 router, 즉 서버에서 return을 render로 하지 말자.(조금만 잘못하면 바로 에러가 난다.)
    - ejs 등의 프론트에서 router로 요청을 보내고, router는 이에 대한 응답을 response 객체에 담아 보내고 종료하도록 해야 한다.
    - res.render(), res.redirect는 가급적 사용하지 않는 것이 좋음.

     ejs >> fetch >> router >> router의 return >> ejs >> ejs에서 다른 ejs로 리다이렉트, 혹은 fetch를 다시 써서 필요한 router로 다시 요청 전송 >>.... 필요한 만큼 반복
  • 패스포트는 여기엔 적지 않겠다. 아직 이해도 제대로 안돼서, 다음 프로젝트 때 써보고 기록해야지

profile
코딩하러 온 사람입니다.

1개의 댓글

comment-user-thumbnail
2024년 2월 22일

협업에서 설계와 문서화, 그리고 소통은 너무 중요하죠.
회사에 가시면 같은 개발자 뿐만 아니라 디자이너, PM/PO, 마케터 등
각자 다른 배경 지식을 가지고 있는 사람들과 함께 일해야하기 때문에
이런 것들이 더욱 중요해지는 것 같습니다.
앞으로도 계속 많은 시행착오 겪어보시기 바랍니다!

답글 달기