새소식

독서

Clean Code 제 2장. 의미 있는 이름

  • -

오늘 읽은 범위 : 2장. 의미 있는 이름


책에서 기억하고 싶은 내용

소프트웨어에서 이름은 어디나 쓰인다. 많이 사용하므로 이름을 잘지으면 여러모로 편하다. 여느 코드 개선 노력과 마찬가지로 이름 역시 나름대로 바꿨다가는 누군가 질책할지도 모른다. 그렇다고 코드를 개선하려는 노력을 중단해서는 안된다. 아래 규칙을 사용하여 코드 가독성을 높히는 연습을 해보자.

이름을 잘 짓는 간단한 규칙

  • 클래스 이름: 동사는 사용하지 않으며 명사나 명사구가 적합하다.(애매하거나 중의적인 명사는 노노)
  • 메서드 이름: 동사나 동사구가 적합하다. 생성자를 오버로딩할때는 static factory method를 사용한다.
    Complex fulcrumPoint = new Complex(23.0); 
    Complex fulcrumPoint = Complex.FromRealNumber(23.0);
  • 의도를 분명히 밝혀라
    • 변수(함수/클래스)의 존재 이유
    • 수행 기능
    • 사용방법
    • 변수나 함수 그리고 클래스의 이름을 이 질문을 모두 답할수 있어야한다. 그러한 노력을 통해 읽는사람으로 하여금 시간을 절약시킬수 있다.
    • 변수 명명법 예시 1
      // Bad Naming
      int d; // 경과시간 (단위: 날짜)
      
      // Good Naming
      int elapsedTimeInDays;
      int daysSinceCreation;
      int daysSinceModification;​
    • 메서드 예시
      // 하는일을 짐작하기 어려운 코드
      public List<int[]> getThem() {
      	List<int[]> list1 = new ArrayList<int[]>();
      	for(int[] : theList){
      		if(x[0] == 4){
      			list1.add(x);
      		};
      	};
      	return list1;
      }
      
      // 조금더 직관적으로 바뀐 메서드
      public List<int[]> getFlaggedCells(){
      	List<int[]> flaggedCells = new ArrayList<int[]>();
      	for(int[] cell : gameBoard){
      		if(cell[STATUS_VALUE] == FLAGGED){
      			fluggedCells.add(cell);
      		};
      	};
      	return flaggedCells;
      };
      
      // 더 나아가 배열대신 간단한 클래스를, 명시적인 함수를 생성해 표현한 메서드
      public List<Cell> getFaggedCells(){
      	List<Cell> flaggedCells =  new ArrayList<Cell>();
      	for(Cell cell : gameBoard){
      		if(cell.isFlagged()){
      			fluggedCells.add(cell);
      		};
      	};
      	return flaggedCells;
      };​
      단순히 이름만 고쳤는데도 함수가 하는일을 이해하기 쉬워졌다. 바로 이것이 좋은 이름이 주는 위력이다.

  • 그릇된 정보를 피하라
    • 그릇된 단서는 코드의 의미를 흐린다.
    • IDE툴들은 자동완성을 지원해준다. 개발자는 객체사용시에 자동완성을 통해 메서드를 가져온다. 이름만 보고 객체를 가져온다면 얼마나 생산성이 올라갈까?!
    • accountList 보다는 accountGroup / bunchOfAccounts / accounts 라 명명한다
    • 실제 컬렉션타입이 List라도 타입을 이름에 넣지 않는 편이 바람직 하다고 한다.
    • 숫자 01과 영어 OI... 진짜 이렇게 변수명을 정하는 사람이 있을까..?
  • 의미있게 구분하라
    • 컴파일러나 인터프리터만 통과하는 코드는 문제를 일으킨다.
    • 연속된 숫자를 덧붙이거나(01, 02 ...) 불용어를 추가하는 방식은 적절하지 못하다
    • 읽는사람이 차이를 알도록 이름을 지어라
    • 의미가 없는 명명법
      getActiveAccount();
      getActiveAccounts();
      getActiveAccountInfo();​
  • 발음하기 쉬운 이름을 사용하라
      class DtaRcrd102{
          private Date genymdhms;
          private Date modymdhms;
          private final String pszqint = "102";
      };
    
      class Customer{
          private Date generationTimeStamp;
          private Date modificationTImeStamp;
          private final String recordId = "102";
      };
    소통방식이 영어권이 아닌 우리나라에서는 조금 색다르게 보인 규칙인것같다. 책에서 제시한 예시를 보면 무슨말을 하는지 이해 할 수 있을것이다.
  • 검색하기 쉬운 이름을 사용하라
    • 문자 하나를 사용하는 이름과 상수는 쉽게 눈에 띄지 않는다
    • 이름 길이는 범위 크기에 비례해야한다.
      ⇒ 변수나 상수를 코드 여러곳에서 사용한다면 검색이 쉬운 이름이 바람직하다는 말이다.
  • 인코딩을 피하라
    문제해결에 집중하는 개발자에게 인코딩은 정신적 부담이다. 인코딩된 이름은 발음도 어려우며 오타가 생기기도 쉽다. 
    • 헝가리식 표기법
      글자 하나에 숫자 하나만 허용했다 (a1, b2 ...)
    • 멤버변수 접두어
      멤버변수에 m_이라는 접두어를 두어 사용하던 방식이다.
      IDE툴들이 멤버변수는 색상을 다르게 표현해주니 이 또한 구닥다리 코드라는 징표가 된다.
    • 인터페이스 클래스와 구현 클래스
    • 도형을 생성하는 Interface인 ShapeFactory가 있다고 가정한다.
      IShapeFactory (Interface) , ShapeFactory(Implement) 와 같은 형식보다는
      ShapeFactory(Interface), ShapeFactoryImpl(Implement)의 형식이 좋다는 말이다.

  • 자신의 기억력을 자랑하지 마라
    • 자신이 아닌 독자가 실제 개념으로 변환해야 하는데 어려움이 있으니 변수명은 자신만 아는 이름으로 사용하면 안된다.
    • 전문가 프로그래머는 명료함이 최고라는 사실을 이해하고 남들이 이해하는 코드를 내놓는다.
  • 기발한 이름은 피하라
    • 특정문화에서만 사용하는 농담은 피하는게 좋다.
    • 이부분도 영어권이라 kill() 대신 whack() 과 같이 표현한다던지.. 명명으로 장난치지 말자.
  • 한 개념에 한 단어를 사용하라
    • 메서드 이름은 독자적이고 일관적이여야한다.
      최신 IDE는 객체에서 자동완성시 객체가 제공하는 메서드를 전부 보여준다.
      굳이 직접 들어가서 주석이나 코드를 살펴보지 않고 메서드명을 통해 입력한다면 생산성이 얼마나 올라갈까!!
  • 말장난을 하지 마라
    • 한 단어를 두가지 목적으로 사용하지 마라
    • 코드를 짤때 집중적인 탐구보단 대충 훑어봐도 이해할수 있는 코드 작성이 목표이다.
    • 코드의 의미를 해독할 책임은 읽는사람이 아닌 작성한 사람이다.
  • 해법 영역에서 가져온 이름을 사용하라
    • 코드를 읽는 사람 또한 개발자다.
    • 기술개념에는 기술이름이 가장 적합한 선택이다.
  • 문제 영역에서 가져온 이름을 사용하라
    • 적절한 기술용어가 없다면 문제영역에서 명명하라
  • 의미 있는 맥락을 추가하라
    firstName, lastName, street, houseNumber, state, city, zipcode 라는 변수가 있다. 훑어 보면 주소라는 사실을 알 수 있다. 하지만 어느 메서드가 state 변수 하나만 사용한다면 이 변수가 주소의 일부라는 사실을 알 수 있을까?
    addr 이라는 접두어를 추가해 쓰면 맥락이 조금더 분명해진다.(addrFirstName, addrState...)
    • 맥락이 분명한 변수 vs 맥락이 불분명한 변수
        // 맥락이 분명한 변수
        public class GuessStatisticsMessage{
            private String number;
            private String verb;
            private String pluralModifier;
      
        public String make(char candidate, int count){
            createPluralDependentMessageParts(count)
            return String.format(
             "There %s %s %s%s", verb, number, candidate, pluralModifier
            );
        }
      
        private void createPluralDependentMessageParts(int count){
            if(count == 0){
                thereAreNoLetters();
            } else if (count == 1){
                thereIsOneLetter();
            } else {
                thereAreManyLetters(count);
            }
        };
      
        private void thereAreNoLetters(){
            number = "no";
            verb = "are";
            pluralModifier = "s";
        };
        private void thereIsOneLetter(){
            number = "no";
            verb = "are";
            pluralModifier = "s";
        };
        private void thereAreManyLetters(int count){
            number = Integer.toString(count);
            verb = "are";
            pluralModifier = "S";
        };
      // 맥락이 분명한 변수
      public class GuessStatisticsMessage{
      	private String number;
      	private String verb;
      	private String pluralModifier;
      
      public String make(char candidate, int count){
      	createPluralDependentMessageParts(count)
      	return String.format(
      	 "There %s %s %s%s", verb, number, candidate, pluralModifier
      	);
      }
      
      private void createPluralDependentMessageParts(int count){
      	if(count == 0){
      		thereAreNoLetters();
      	} else if (count == 1){
      		thereIsOneLetter();
      	} else {
      		thereAreManyLetters(count);
      	}
      };
      
      private void thereAreNoLetters(){
      	number = "no";
      	verb = "are";
      	pluralModifier = "s";
      };
      private void thereIsOneLetter(){
      	number = "no";
      	verb = "are";
      	pluralModifier = "s";
      };
      private void thereAreManyLetters(int count){
      	number = Integer.toString(count);
      	verb = "are";
      	pluralModifier = "S";
      };​
  • 불필요한 맥락을 없애라
    • 애플리케이션의 핵심 도메인을 모든 클래스 이름에 추가하지 말라.

오늘 읽은 소감은

  • 나만 이해할수 있는 변수명을 메서드에 종종 추가했었던 경험이 매우 많다. 문제가 생겨도 내가 수정하고 내가 유지보수를 할거라는 안일한 생각으로 그렇게 코드를 짰던것같다. 물론 지금은 유지보수를 내가 하고 있지 않지만 현재 유지보수를 하는 사람에게 나는 코드를 그지같이 짠 사람이라고 생각될것이다.
    나는 누군가에게든 좋은 개발자였다는 인식을 남기고싶다. 사소한 명명법에도 신중하게 작성하여 ‘아 그래도 이사람이 사소한거에 신경은 썼구나' 라는 생각은 들게 노력해 봐야겠다.

궁금한 내용이 있거나, 잘 이해되지 않는 내용

  • 해법영역 (Solution Domain)
  • 문제영역 (Problem Domain)

기존 단어만 보고는 어떤 뜻인지 정확히 모르겠다. 좀 더 자세히 찾아봐야 할 것 같다.

'독서' 카테고리의 다른 글

Clean Code 제 5장. 형식 맞추기  (0) 2022.03.01
Clean Code 제 4장. 주석  (0) 2022.02.25
Clean Code 제 3장. 함수  (0) 2022.02.23
Clean Code 제 1장. 깨끗한 코드  (0) 2022.02.19
사례를 통해 배우는 SRP  (0) 2021.07.24
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.