ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Clean Code 1~2장
    Backend/책 정리 2023. 2. 28. 02:29

    이번에 새로 Clean Code 책 스터디를 진행하며 일주일에 한 번씩 책을 읽고 돌아가며 발표를 하기로 했다. 기존처럼 개인 노션에 정리하고 블로그에는 좀 더 고민한 글을 쓸까 고민하다, 개인적으로 오히려 이런 다짐이 부담으로 느껴져서 잘 안쓰게 되는 것 같아 앞으로는 노션에 정리하듯이 블로그에도 조금씩 정리를 할까 한다.

     

    그 첫 시작이 Clean Code를 정리하는것으로 정했다. 앞으로 꾸준히 매주 일정 분량씩 읽고 정리를 남기도록 하겠다.

     

    1장 - 깨끗한 코드

    나쁜 코드는 결국 생산성 저하로 이어진다. 책에서 소개한 내용으로는 회사가 사망한 원인이 나쁜 코드 탓이라고 할 정도로 나쁜 코드로 인해 생산성이 떨어진다고 얘기를 한다.

    나도 작년에 공모전을 나가면서 정말 급하게 코드를 작성하고 제출한 경험이 있는데, 당시에는 시간이 없어서 테스트 코드를 작성하지도 않고 나중에 한번에 고치겠다는 생각으로 코드를 구현했다. 공모전이 끝나고 개인적으로 다시 코드를 리팩터링하려고 봤더니 정말 이해가 어려운 코드들이 생각보다 많았던것 같다. 결국 도저히 퇴근 후 손이 가지 않아서 리팩터링을 포기하였고 이때 정말 코드를 잘 작성해야겠구나 라는 생각을 했다.

     

    빨리 가능 유일한 방법은, 언제나 코드를 최대한 깨끗하게 유지하는 습관이다.

    위 문구를 기억하며 항상 깨끗한 코드를 작성하기 위해 노력해야겠다. 깨끗한 코드를 위해 중요한 열쇠는 코드 감각이다. 코드 감각이 있는 프로그래머는 나븐 모듈을 보면 좋은 모듈로 개선할 방안을 떠올린다. 코드 감각으로 최고 방안을 선택한 후 여기서 거기까지 이동하는 경로를 계획한다고 한다. 결국 책을 꾸준히 학습해서 코드 감각을 얻는 것이 이번 스터디의 목표라고 할 수 있을것 같다.

     

    책에서는 다양한 프로그래머들의 의견을 소개해준다.

    1. 비야네 스트롭스트룹

    • 깨끗한 코드는 한 가지를 제대로 한다.
    • 깨끗한 코드는 세세한 사항까지 꼼꼼하게 처리하는 코드다.

     

    2. 그레디 부치

    • 깨끗한 코드는 단순하고 직접적이다.
    • 깨끗한 코드는 잘 쓴 문장처럼 읽힌다.
    • 깨끗한 코드는 결코 설계자의 의도를 숨기지 않고 오히려 명쾌한 추상화와 단순한 제어문으로 가득하다.

     

    3. 데이브 토마스

    • 깨끗한 코드는 작성자가 아닌 사람도 읽기 쉽고 고치기 쉽다.
    • 단위 테스트 케이스와 인수 테스트 케이스가 존재해야 한다.
    • 테스트 케이스가 없는 코드는 깨끗한 코드가 아니다.

     

    4. 마이클 페더스

    • 깨끗한 코드는 언제나 누군가 주의 깊게 짰다는 느낌을 준다.

     

    5. 론 제프리스

    • 중복을 피하라
    • 한 기능만 수행하라
    • 제대로 표현해라
    • 작게 추상화하라

     

    6. 워드 커닝햄

    • 깨끗한 코드는 읽으면서 놀랄 일이 없어야 한다.
    • 코드가 그 문제를 풀기 위한 언어처럼 보인다면 아름다운 코드다 -> 언어를 단순하게 보이도록 만드는 책이이 우리에게 있다.
    코드를 짤 때는 자신이 저자라는 사실을, 여러분의 노력을 보고 판단을 내릴 독자가 있다는 사실을 기억하길 바란다.
    캠프장을 처음 왔을 때보다 더 깨끗하게 해놓고 떠나라

     

    2장 - 의미 있는 이름

    2장에서는 이름을 잘 짓는 간단한 규칙을 몇 가지 소개해주고 있다.

     

    1. 의도를 분명히 밝혀라

    • 이름들은 다음 질문에 모두 답해야한다.
      • 존재 이유는
      • 수행 기능은
      • 사용 방법은

     

    • 따로 주석이 필요하다면 의도를 분명히 드러내지 못했다는 말이다.
    public List<Cell> getFlaggedCells() {
    	List<Cell> flaggedCells = new ArrayList<Cell>();
    	for (Cell cell : gameBoard) {
    		if (cell.isFlagged()) {
            	flaggedCells.add(cell);
    		}
    	}
    	return flaggedCells;
    }

    위 코드에서 변수명만 보더라도 해당 함수가 어떤 일을 하는지 훨씬 이해하기 쉬운 것을 알 수 있다.

     

     

    2. 그릇된 정보를 피하라

    • 나름대로 널리 쓰이는 의미가 있는 단어를 다른 의미로 사용하면 안 된다.
    • 여러 계정을 그룹으로 묶을 때, 실제 List가 아니라면 accountList라 명명하지 않는다.
    • 단순히 accountGroup, Accounts라 명명하는게 좋다.
    • 흡사한 이름을 사용하지 않도록 주의한다.
    • 유사한 개념은 유사한 표기법을 사용하자 -> 일관성이 떨어지는 표기법은 그릇된 정보다.

     

    3. 의미 있게 구분하라

    • 컴파일러나 인터프리터만 통과하려는 생각으로 코드를 구현하는 프로그래머는 스스로 문제를 일으킨다.
    • 연속적인 숫자를 덧붙인 이름(a1, a2, a3...)은 의도적인 이름과 정반대다
    • 저자 의도가 전혀 드러나지 않는다.
    • 불용어를 추가한 이름 역시 아무런 정보도 제공하지 못한다.
      • Product라는 클래스가 있을 때 ProductInfo, ProductData라는 다른 클래스가 있다면 개념을 구분하지 않고 이름만 달리한 경우다.
    • 변수 이름에 variable 이라는 단어는 단연코 금물이다. 표에 table 이라는 단어도 마찬가지이다.
    읽는 사람이 차이를 알도록 이름을 지어야 한다.

     

    4. 발음하기 쉬운 이름을 사용해라

    • 정의상으로 단어는 발음이 가능해야하며
    • 발음하기 쉬운 이름을 선택해야 한다.

     

    5. 검색하기 쉬운 이름을 사용하라

    • 문자 하나를 사용하는 이름과 상수는 텍스트 코드에서 쉽게 눈에 띄지 않는다는 단점이 있다.
    • 이런 관점에서 긴 이름이 짧은 이름보다 좋다.
    • 검색하기 쉬운 이름이 상수보다 좋다.

     

    6. 인코딩을 피하라

    • 자바 프로그래머는 변수 이름에 타입을 인코딩할 필요가 없다.
    • 인터페이스(Interface) 클래스와 구현 클래스(concrete)
      • 저자는 인터페이스 이름은 접두어를 붙이지 않는 편이 좋다고 생각한다.
      • 따라서 ShapeFactory라는 인터페이스와 이를 구현한 클래스가 있다면 인터페이스의 이름을 ShapeFactory라고 하고 구현 클래스를 ShapeFactoryImp나 CShapeFactory로 명명하겠다.

     

    7. 자신의 기억력을 자랑하지 마라

    • 전문가 프로그래머는 명료함이 최고라는 사실을 이해한다.

     

    8. 클래스 이름

    • 클래스 이름과 객체 이름은 명사나 명사구가 적합하다.

     

    9. 메서드 이름

    • 메서드 이름은 동사나 동사구가 적합하다.
    생성자를 중복정의할 때는 정적 팩토리 메서드를 사용한다. 메서드는 인수를 설명하는 이름을 사용한다.
    Complex fulcrumPoint = Complex.FromRealNumber(23.0);
    
    Complex fulcrumPoint = new Complex(23.0);

    위 코드에서 정적 팩토리 메서드를 사용한 메서드가 훨씬 이해하기 명확하다는 것을 알 수 있다.
    정적 팩토리 메서드에 대해서는 추가로 글을 작성하도록 하겠다.

     

     

    10. 기발한 이름은 피하라

    • 재미난 이름보다 명료한 이름을 선택해라
    • 특정 문화에서만 사용하는 농담은 피하고 의도를 분명하고 솔직하게 표현해라

     

    11. 한 개념에 한 단어를 사용하라

    • 추상적인 개념 하나에 단어 하나를 선택해 이를 고수한다.
      • 예를 들어 똑같은 메서드를 클래스마다 fetch, retrieve, get으로 제각각 부르면 혼란스럽다.
    • 메서드 이름은 독자적이고 일관적이어야 한다.
    • 이름이 다르면 독자는 당연히 클래스도 다르고 타입도 다르리라 생각한다.
    • 일관성 있는 어휘는 코드를 사용할 프로그래머가 반갑게 여길 선물이다.

     

    12. 말장난을 하지 마라

    • 한 단어를 두 가지 목적으로 사용하지 마라
    • 예를 들어 두 단어를 이어주는 메서드로 add라고 부른다면, 새롭게 집합에 값 하나를 추가하는 메서드의 이름을 add라 부르게 되면 서로 다른 맥락으로 사용되기 때문에 insert나 append라는 이름이 적당하다.

     

    13. 해법 영역에서 가져온 이름을 사용하라

    • 코드를 읽을 사람도 결국 프로그래머다
    • 따라서 전산 용어를 사용하는 것은 괜찮다.
    • 기술 개념에 기술 이름이 가장 적합한 선택이다.

     

    14. 문제 영역에서 가져온 이름을 사용하라

    • 적절한 프로그래머 용어가 없다면 문제 영역에서 이름을 가져온다.
    • 우수한 프로그래머와 설계자라면 해법 영역과 문제 영역을 구분할 줄 알아야 한다.
    • 문제 영역 개념과 관련이 깊은 코드라면 문제 영역에서 이름을 가져와야 한다.
    문제 영역 : 실제 도메인의 전문가에게 의미를 물어 파악할 수 있도록 문제 영역에서 이름을 가져오자.
    해법 영역 : 개발자라면 당연히 알고 있을 전산용어, 알고리즘 이름, 패턴 이름, 수학 용어 등은 사용하자.

     

    15. 의미 있는 맥락을 추가하라

    • 대다수의 이름은 스스로 의미가 분명하지 못할 수 있다.
    • 이때 클래스, 함수, 이름 공간에 넣어 맥락을 부여한다.
    • 모든 방법이 실패하면 마지막 수단으로 접두어를 붙인다.

    - 예를 들어 firstName, lastName, street, houseNumber, city, state, zipcode 라는 변수들이 있다면 변수를 전부 봐야 주소라는 사실을 알 수 있다. 이때 addr라는 접두어를 추가해 addrFirstName, addrLastName, addrState 라고 작성한다면 맥락이 좀 더 분명해진다.

    적어도 변수가 좀 더 큰 구조에 속한다는 사실이 독자들에게는 분명해진다.

    - Address라는 클래스를 생성하면 더 좋다.

     

    아래 코드를 보자

    private void printGuessStatistics(char candidate, int count) {
        String number;
        String verb;
        String pluralModifier;
    
        if (count == 0) {
            number = "no";
            verb = "are";
            pluralModifier = "s";
        } else if (count == 1) {
            number = "1";
            verb = "is";
            pluralModifier = "";
        } else {
            number = Integer.toString(count);
            verb = "are";
            pluralModifier = "s";
        }
        String guessMessage = String.format(
                "There $s $s $s$s", verb, number, candidate, pluralModifier
        );
        System.out.println(guessMessage);
    }

    일단 함수가 좀 길고 세 변수를 함수 전반에서 사용한다.

    따라서 세 변수를 GuessStatisticsMessage라는 클래스를 만든 후 넣어주면, 세 변수는 맥락이 분명해진다.

    아래 코드는 위 코드를 개선한 코드이다.

    함수를 쪼개면서 훨씬 가독성 좋은 코드로 바뀐것을 알 수 있다.

    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 = "1";
            verb = "is";
            pluralModifier = "";
        }
    
        private void thereAreManyLetters(int count) {
            number = Integer.toString(count);
            verb = "are";
            pluralModifier = "s";
        }
    }

     

    16. 불필요한 맥락을 없애라

    • 의미가 분명한 경우에 한해 일반적으로 짧은 이름이 긴 이름보다 좋다.
    • accountAddress와 customAddress는 Address 클래스 인스턴스로는 좋은 이름이나 클래스 이름으로는 적합하지 못하다.

    좋은 이름을 선택하는 능력은 기술, 비즈니스, 관리 문제가 아니라 교육 문제이다.

    좋은 이름을 선택하려면 설명 능력이 뛰어나야 하고 문화적인 배경이 같아야하기 때문이다.

     

    사람들이 이름을 바꾸지 않으려는 이유 하나는 다른 개발자가 반대할까 두려워서다. 하지만 오히려 좋은 이름으로 바꿔주면 반갑고 고맙다.

     

    따라서 이름 역시 나름대로 바꿨다가는 누군가 질책할지도 모르지만, 그렇다고 코드를 개선하려는 노력을 중단해서는 안 된다.

    'Backend > 책 정리' 카테고리의 다른 글

    Clean Code 12 ~ 13 장  (0) 2023.04.04
    Clean Code 9 ~ 11 장  (0) 2023.03.28
    Clean Code 7~8 장  (0) 2023.03.21
    Clean Code 5~6 장  (0) 2023.03.10
    Clean Code 3~4장  (2) 2023.03.07

    댓글

Designed by Tistory.