본문 바로가기
개발/코드컨벤션

개인 코드 컨벤션 정리

by goodchuck 2024. 5. 22.

목차

     

     

    정리하기에 앞서

    개발자는 혼자서도 개발을 할 수도있지만 다양한 사람과 협업을 해야할 가능성이 더 높습니다.이 때 아무리 뛰어난 개발자더라도 자신만의 개발로 막 개발을 한다면 나중에 협업을 할때 다른 사람의 러닝커브가 생길 수 도 있고다른 사람과의 협업이 더 힘들어져 개발속도가 늦춰질 수 도있습니다.그래서 코드 컨벤션을 정의함으로써 한사람이 개발을 한 것처럼 그리고 다른사람이 오더라도 많은 자원이 소모하지 않게 끔 하려고 합니다.그렇기에 일단 협업도 좋지만 자기 자신도 일단 규칙을 어느정도 세우는게 중요하다 싶어서 해당 포스팅글을 작성하려고합니다.

     

    자세하진 않더라도 조금씩 규칙을 정하면서 내용을 추가할 예정입니다!

     

    해당 컨벤션은 완벽하지 않고 주관적인 영역과 장단점을 통해 자신만의 방법을 고른 것이므로 언제든지 바뀔 수 있습니다.

     

    폴더 컨벤션

    위 사진은 next.js에서의 src폴더 목록입니다. 

    Next.js는 app라우터를 사용하는 13버전 이후 기준입니다.

     

    app

    • 앱의 루트 컴포넌트나 주요 설정 파일을 포함합니다. 예를 들어, 앱 초기화 로직이나 공통 레이아웃 등을 포함할 수 있습니다.

     

    components

    • 재사용 가능한 UI 컴포넌트들이 위치합니다. 버튼, 입력 폼, 모달 등과 같은 작은 단위의 컴포넌트들이 포함됩니다.

    constants

    • 애플리케이션에서 사용되는 상수들을 정의합니다. 예를 들어, API 엔드포인트, 특정 키 값, 설정 값 등을 이 폴더에 모아놓습니다.

     

    containers

    • 페이지 수준의 컨테이너 컴포넌트들이 위치합니다. 이 컴포넌트들은 주로 상태 관리를 담당하며, 여러 하위 컴포넌트를 조합하여 화면을 구성합니다.

     

    dummyData

    • 테스트용 데이터나 샘플 데이터를 포함합니다. 실제 데이터를 사용하기 전, 개발 중에 가짜 데이터를 사용하여 작업할 때 유용합니다.

    enums

    • 열거형(enum) 타입을 정의합니다. 상태 값, 타입 값 등 여러 개의 상수 값들을 하나의 그룹으로 묶어 사용할 때 사용됩니다.

     

    hooks

    • 커스텀 훅(custom hooks)을 포함합니다. React 훅을 활용하여 상태 관리, 사이드 이펙트 처리 등의 로직을 재사용 가능하게 분리합니다.

     

    layout

    • 페이지의 레이아웃을 정의하는 컴포넌트가 위치합니다. 헤더, 푸터, 사이드바 등 공통적으로 사용되는 레이아웃 컴포넌트를 포함합니다.

     

    libs

    • 외부 라이브러리나 유틸리티 함수들이 위치합니다. 예를 들어, API 호출 함수, 데이터 포맷팅 함수 등이 포함됩니다.

     

    services

    • 비즈니스 로직이나 API 호출 관련 코드가 포함됩니다. 백엔드와의 통신 로직을 이곳에 위치시켜, 컴포넌트 코드와 분리합니다.

     

    types

    • TypeScript의 타입 정의 파일들이 위치합니다. 인터페이스나 타입을 정의하여 코드의 타입 안전성을 보장합니다.

     

    utils

    • 유틸리티 함수들이 위치합니다. 여러 곳에서 재사용 가능한 함수들을 모아놓는 폴더입니다. 예를 들어, 날짜 포맷팅 함수, 문자열 처리 함수 등이 포함될 수 있습니다.

     

     파일 내에서의 코드 컨벤션

    코드 스타일

    • 코드 스타일은 기본적으로 eslint와 prettier를 이용한 airbnb형식에서 일부만 변경해서 사용하려고 한다.

     .eslintrc.json

    {
      "extends": [
        "next/core-web-vitals",
        "airbnb",
        "airbnb/hooks",
        "plugin:@typescript-eslint/recommended",
        "plugin:prettier/recommended"
      ],
      "plugins": ["@typescript-eslint", "prettier"],
      "parser": "@typescript-eslint/parser",
      "parserOptions": {
        "ecmaVersion": 2020,
        "sourceType": "module",
        "ecmaFeatures": {
          "jsx": true
        },
        "project": "./tsconfig.json"
      },
      "rules": {
        "prettier/prettier": ["error", { "endOfLine": "lf" }],
        "react/react-in-jsx-scope": "off",
        "import/no-extraneous-dependencies": ["error", { "devDependencies": true }],
        "@typescript-eslint/explicit-module-boundary-types": "off",
        "react/jsx-filename-extension": [1, { "extensions": [".tsx", ".jsx"] }],
        "import/extensions": [
          "error",
          "ignorePackages",
          {
            "js": "never",
            "jsx": "never",
            "ts": "never",
            "tsx": "never"
          }
        ]
      },
      "settings": {
        "react": {
          "version": "detect"
        },
        "import/resolver": {
          "node": {
            "extensions": [".js", ".jsx", ".ts", ".tsx"]
          },
          "typescript": {
            "alwaysTryTypes": true,
            "project": "./tsconfig.json"
          }
        }
      }
    }

     

     .prettierrc

    {
      "singleQuote": true,
      "trailingComma": "all",
      "printWidth": 80,
      "tabWidth": 2,
      "semi": true,
      "endOfLine": "lf"
    }

     

     Next.js && React

    hook

     훅의 이름 규칙

    • 접두사 : 모든 훅은 'use' 접두사로 시작해야 한다. 예를 들어, 'useUser', 'useAuth', 'useFetch'
    • CamelCase : 훅의 이름은 CamelCase를 사용한다.

     파일 이름 및 위치

    • 파일 이름 : 훅을 정의하는 파일의 이름은 훅의 이름과 일치시키며, CamelCase를 사용한다. 예를 들어 'useUser.ts', 'useAuth.ts'
    • 폴더 구조 : 훅은 'src/hooks' 또는 'src/libs/hooks' 폴더에 저장한다.

     타입스크립트 타입 정의

    • 타입 명시 : 훅의 반환 타입과 인자 타입을 명시한다.
    • 인터페이스 사용 : 복잡한 타입 정의는 인터페이스를 사용한다.

     기본 내보내기

    • 단일 훅 : 파일 내에 단일 훅이 있는 경우 기본 내보내기(default export)를 사용한다.
    • 여러 훅 : 파일 내에 여러 훅이 있는 경우 명시적 내보내기(named export)를 사용한다.

     TypeScript

    type

    • 기본 타입 별칭, 유니언 타입, 튜플, 교차 타입 등을 정의할 때 사용한다.
    • 객체의 구조를 정의할 때도 사용할 수 있지만, 주로 간단한 객체나 복잡한 타입 조합을 정의할 때 사용한다.

     이름 짓기 규칙

    • 타입 이름은 PascalCase를 사용한다.
    • 약어는 대문자로 표기한다.
    // 좋은 예
    type UserID = string | number;
    type HTTPResponse = 'success' | 'error';
    
    // 나쁜 예
    type userid = string | number;
    type httpresponse = 'success' | 'error';

     

     기본 타입 별칭

    • 복잡한 타입을 더 쉽게 이해할 수 있도록 별칭을 사용한다.
    • 타입 별칭은 가능한 구체적이어야 한다.
    // 좋은 예
    type Email = string;
    type Point = {
      x: number;
      y: number;
    };
    
    // 나쁜 예
    type E = string;
    type P = {
      x: number;
      y: number;
    };

     

     유니언 타입

    • 유니언 타입을 정의할 때는 가능한 구체적으로 작성한다.
    // 좋은 예
    type Status = 'success' | 'error' | 'loading';
    
    // 나쁜 예
    type Status = string;

     

     교차 타입(Intersection Types)

    • 두 개 이상의 타입을 합쳐야 할 때는 교차 타입을 사용한다.
    // 좋은 예
    type Person = {
      name: string;
      age: number;
    };
    
    type Employee = Person & {
      employeeId: number;
    };
    
    // 나쁜 예
    type Person = {
      name: string;
      age: number;
    };
    
    type Employee = {
      name: string;
      age: number;
      employeeId: number;
    };

     

     객체 타입 정의

    • 객체의 구조를 정의할 때는 명확하고 구체적으로 작성합니다.
    // 좋은 예
    type Address = {
      street: string;
      city: string;
      country: string;
    };
    
    // 나쁜 예
    type Address = {
      s: string;
      c: string;
      co: string;
    };

     

     인덱스 시그니처

    • 객체가 동적 속성을 가질 수 있을 때는 인덱스 시그니처를 사용한다.
    // 좋은 예
    type Dictionary = {
      [key: string]: string;
    };
    
    // 나쁜 예
    type Dictionary = {
      [key: string]: any;
    };

     

     타입 구성

    • 타입을 구성할 때는 필요한 경우 타입을 조합하거나 재사용하여 작성한다.
    type Point = {
      x: number;
      y: number;
    };
    
    type Circle = {
      center: Point;
      radius: number;
    };

     

     코드 컨벤션 예시

    // 기본 타입 별칭
    type ID = string | number;
    
    // 유니언 타입
    type Status = 'success' | 'error' | 'loading';
    
    // 교차 타입
    type Person = {
      name: string;
      age: number;
    };
    
    type Employee = Person & {
      employeeId: number;
    };
    
    // 객체 타입 정의
    type Address = {
      street: string;
      city: string;
      country: string;
    };
    
    // 인덱스 시그니처
    type Dictionary = {
      [key: string]: string;
    };
    
    // 타입 구성
    type Point = {
      x: number;
      y: number;
    };
    
    type Circle = {
      center: Point;
      radius: number;
    };

     

    인터페이스

     인터페이스 사용할때?

    • 객체의 구조를 정의할 때 사용한다.
    • 주로 클래스나 큰 규모의 객체 구조를 정의할 때 사용한다.

     이름 짓기 규칙

    • 인터페이스 이름은 보통 'I'접두사를 사용하지 않는다. 대신, 명확하고 직관적인 이름을 사용한다.
    • PascalCase를 사용하여 인터페이스 이름을 정의한다.
    // 좋은 예
    interface UserProfile {
      name: string;
      age: number;
      email: string;
    }
    
    // 나쁜 예
    interface IUserProfile {
      name: string;
      age: number;
      email: string;
    }

     

     선언 위치

    • 인터페이스는 해당 인터페이스를 사용하는 파일 상단에 정의하거나, 여러 파일에서 사용되는 경우 별도의 'types'폴더에 정의합니다.
    // 파일 상단에 정의
    interface UserProfile {
      name: string;
      age: number;
      email: string;
    }
    
    // 또는 types 폴더에 정의 (예: src/types/UserProfile.ts)

     

     

     사용 예시 포함

    • 인터페이스 정의와 함께 해당 인터페이스를 사용하는 예시를 주석으로 포함하면 가독성이 높아집니다.
    interface UserProfile {
      name: string;
      age: number;
      email: string;
    }
    
    // Example usage:
    const user: UserProfile = {
      name: 'John Doe',
      age: 30,
      email: 'john.doe@example.com',
    };