본문 바로가기

Programming/Java & JSP & Spring

나만의 코딩컨벤션 작성하기(Spring, Java, Naming, 구조, 코드 작성법 등)

현재(2020. 04) 나만의 코딩 컨벤션을 기록으로 남겨 계속해서 보완해나갈 생각이다.

물론 회사에서 하는 작업물은 나의 스타일과 안맞더라도 회사의 코딩컨벤션을 따르는 것이 맞다.

하지만, 회사의 컨벤션을 그냥 무심코만 따라하기만 하면 잘못된 스타일이 몸에 밸수도 있고 나의 스타일이 그냥 회사에 맞춰지게 된다.

나만의 코딩 컨벤션을 기록으로 남기고 꾸준히 보완해나갈 생각이다.

코딩컨벤션이란

어느 블로그에서 본 글인데, 가장 코딩컨벤션을 쉽게 표현한 것 같아 인용해서 설명하면 다음과 같다.

프로그래밍 언어는 한글, 영어, 일본어 등과 흡사하다. 한글에도 지역마다 사투리가 존재하고 그 지역에서 원활한 소통을 하려면 그 지역의 사투리를 잘 배우고 사용해야 한다.

이는 프로그래밍 세계에서도 마찬가지이다. 코딩 스타일에서 표준이라는 것은 존재하지 않지만, 동일한 회사 내에서, 최소한 동일한 팀 내부에서는 같은 코딩 스타일을 결정하고 관리하고 유지하는 것이 원활한 소통과 작업 효율을 증가시키는 길이 될 것이다.

가장 중요한 점은 어떤 코딩컨벤션을 선택하느냐가 중요한 것이 아니라, 통일된 기준으로 코드를 작성하는 것이 중요

기본적인 사항

코드 스타일을 적용시키고 항상 코딩 작업을 마친 후에는 reformat code(단축키 : cmd + alt + L)을 통해 간격, 공백등의 코드 스타일을 적용시킨다. (코드 스타일을 IDE에 적용시켰다는 전제하에)

또한 코드에 사용되지 않은 라이브러리를 삭제해준다. (단축키 : ctrl + alt + O)

Naming

  1. 기본적으로 네이밍은 누구나 알 수 있는 쉬운 단어를 선택한다.
    • 우리는 외국인이 아니다. 쓸데없이 어려운 고급 어휘를 피한다.
  2. 변수는 CamelCase를 기본으로 한다.
    • userEmail, userCellPhone ...
  3. URL, 파일명 등은 kebab-case를 사용한다.
    • /user-email-page ...
  4. 패키지명은 단어가 달라지더라도 무조건 소문자를 사용한다.
    • frontend, useremail ...
  5. ENUM이나 상수는 대문자로 네이밍한다.
    • NORMAL_STATUS ...
  6. 함수명은 소문자로 시작하고 동사로 네이밍한다.
    • getUserId(), isNormal() ...
  7. 클래스명은 명사로 작성하고 UpperCamelCase를 사용한다.
    • UserEmail, Address ...
  8. 객체 이름을 함수 이름에 중복해서 넣지 않는다. (= 상위 이름을 하위 이름에 중복시키지 않는다.)
    • line.getLength() (O) / line.getLineLength() (X)
  9. 컬렉션은 복수형을 사용하거나 컬렉션을 명시해준다.
    • List ids, Map<User, Int> userToIdMap ...
  10. 이중적인 의미를 가지는 단어는 지양한다.
    • event, design ...
  11. 의도가 드러난다면 되도록 짧은 이름을 선택한다.
    • retreiveUser() (X) / getUser() (O)
    • 단, 축약형을 선택하는 경우는 개발자의 의도가 명백히 전달되는 경우이다. 명백히 전달이 안된다면 축약형보다 서술형이 더 좋다.
  12. 함수의 부수효과를 설명한다.
    • 함수는 한가지 동작만 수행하는 것이 좋지만, 때에 따라 부수 효과를 일으킬 수도 있다.
      fun getOrder() {
        if (order == null) {
            order = Order()
        }
      return order
      }
    • 위 함수는 단순히 order만 가져오는 것이 아니라, 없으면 생성해서 리턴한다.
    • 그러므로 getOrder() (X) / getOrCreateOrder() (O)
  13. LocalDateTime -> xxxAt, LocalDate -> xxxDt로 네이밍
  14. 객체를 조회하는 함수는 JPA Repository에서 findXxx 형식의 네이밍 쿼리메소드를 사용하므로 개발자가 작성하는 Service단에서는 되도록이면 getXxx를 사용하자.

Structure

구조 설계에 대한 고민은 항상하기 마련이다. 좋은 설계를 위해 꾸준히 고민하고 리팩토링 작업하는 것을 지향한다.

  1. 패키지는 목적별로 묶는다.
    • user(User 관련 패키지), coupon(쿠폰 관련 패키지)
  2. Controller에서는 최대한 어떤 Service를 호출할지 결정하는 역할과 Exception처리만을 담당하자.
    • Controller 단에서 로직을 구현하는 것을 지양한다.
    • Controller의 코드 라인 수를 줄이자는 뜻은 절대 아니다.
  3. 하나의 메소드와 클래스는 하나의 목적을 두게 만든다.
    • 하나의 메소드 안에서 한가지 일만 해야한다.
    • 하나의 클래스 안에서는 같은 목적을 둔 코드들의 집합이여야한다.
  4. 메소드와 클래스는 최대한 작게 만든다.
    • 메소드와 클래스가 커진다면 하나의 클래스나 메소드 안에서 여러 동작을 하고 있을 확률이 크다.
    • 수많은 책임을 떠안은 클래스를 피한다. 큰 클래스 몇 개가 아니라 작은 클래스 여럿으로 이뤄진 시스템이 더욱 바람직하다.
    • 클래스 나누는 것을 두려워하지 말자.
  5. 도메인 서비스를 만들어지는 것을 피하자.
    • User라는 도메인이 있을 때, UserService로 만드는 것을 피한다.
    • 이렇게 도메인 네이밍을 딴 서비스가 만들어지면 자연스레 수많은 책임을 떠안은 큰 클래스로 발전될 가능성이 높다.
    • 기능 별로 세분화해서 만들어보자. (UserRegisterService, UserEmailService 등...)

Programming

  1. 반복되는 코드를 작성하지 않는다.
    • 단, 테스트코드는 예외로 한다.
  2. 변수는 최대한 사용하는 위치에 가깝게 사용한다.
  3. 파라미터 변수와 내부 변수를 구별할 땐 언더바가 아닌 this로 구별한다.
    • this.name = name (O) / name = _name (X)
    • 추가적으로 언더바를 prefix로 사용하는 것을 지양하자.
  4. 코드의 길이가 짧고 명료한 것도 좋지만, 가독성이 현저히 떨어진다면 코드를 좀 더 풀어쓴다.
    • 무조건적으로 코드가 짧은 것이 좋다고 생각하지 않는다. 다른 개발자가 본다면 가독성이 현저히 떨어진다.
    • 특히나 최신 언어(kotlin 등)의 경우 코드의 길이를 현저히 줄일 수도 있지만, 제3자의 입장에서 봐도 어느정도 가독성이 있는지 다시 한번 확인하는 작업을 하자.
  5. 모든 예외는 무시하지말고 처리한다. 만약 예외를 처리하지 않을거라면 그 이유에 대해서 명확하게 주석을 남긴다.
  6. 예외를 던질 때는 최대한 세부적인 Exception(= Custom Exception)을 던진다.
    • 실패한 코드의 의도를 파악하려면 호출 스택트레이스만으로 부족하다.
    • 오류 메세지에 전후 상황의 정보를 담아 예외와 함께 던진다.
  7. 예외 케이스가 발생할 확률이 있는 경우, 가능한 빨리 리턴 또는 예외를 던지도록 작성한다.
    • 쓸데없이 정상로직을 태울 필요가 없게한다.
      if(!정상) {
        throw err;
      }
      정상 로직
      }
  8. 조건이 복잡한 경우 임시 boolean 변수를 만들어 단순화한다.
  9. 조건문에 부정조건을 넣는 것을 피한다.
    • if(status.isNormal()) (O) / if(!status.isAbnormal()) (X)
  10. 최대한 객체 타입 대신 기본 자료형을 선택하고, 생각지도 못한 Autoboxing이 발생하지 않도록 유의한다.