Readable Code

Hani·2025년 3월 19일
0

출처 : 박우빈 강사님의 『Readable Code: 읽기 좋은 코드를 작성하는 사고법

왜 클린 코드를 지향해야하는가?

코드를 처음 보는 사람도 직관적으로 동작을 파악하도록 하여, 유지보수성과 확장성을 높이기 위해서이다. 즉, 미래의 시간과 자원을 절약하기 위해서이다.

그렇다면, 어떻게 코드의 가독성을 높일 수 있을까? 바로 코드를 추상화시키는 것이다.

추상과 구체

우리는 자연스럽게 일상생활 속에서도 추상과 구체를 통해 대화를 한다.
아래의 예시를 살펴보자.

[추상] 부산 맛집 검색해보자!
[구체] 한반도의 남동단에 자리잡고 있고, 바다에 면한 남쪽을 제외하고는 경상남도와 접하고 있으며, 남으로는 대한해협에 면해 있고, 북으로는 울산광역시와 양산시의 동면과 물금읍, 서로는 김해시의 대동면과 경계를 이루고 있는 곳에 대해 검색 엔진의 웹 크롤러가 크롤링해서 웹 페이지의 내용을 분석하고 중요 키워드나 메타데이터를 추출하여 검색 색인 저장 후 사용자의 검색어와 일치하거나 연관성이 높은 문서를 역색인을 통해 찾고 순위를 매긴 후 뜨는 검색 결과 페이지를 확인해보자.

추상화된 정보를 바탕으로 구체 정보를 유추하고, 대답을 추상화하여 상대에게 전달하면서 대화를 진행한다.

이 과정이 가능한 이유는,
추상화된 정보와 문맥을 통해 구체 정보를 파악할 수 있기 때문이다.

즉, 추상화에서 정보문맥은 핵심 요소이다.

적절한 추상화로 복잡한 데이터와 로직을 단순화하여 읽기 쉽도록 만들자.

  • 적절한 추상화란, 해당 도메인의 문맥 안에서 정말 중요한 핵심 개념만 남겨서 표현하는 것.



1. 이름 짓기

이름을 짓는다는 것은 추상적 사고를 기반으로 한다.

  • 단수와 복수 구분하기
  • 이름 줄이지 않기
  • 은어/방언 사용하지 않기
  • 좋은 코드를 보고 습득하기

단축키(윈도우, 맥) : shift + f6

2. 메서드 추상화

한 문단의 주제는 반드시 하나인 것처럼 메서드의 주제는 반드시 하나이다.

메서드 추출을 통해 의미 단위를 명확하게 할 수 있다.


1. 파라미터와 연결지어 풍부한 의미를 전달 가능하다.

ex) makeCountSummaryOf(attendApplications)

2. 파라미터의 타입, 개수, 순서를 통해 의미 전달이 가능하다.
예를 들어, 아래와 같이 String localDate를 파라미터로 넘겨줘야한다면
yyyy-MM-dd를 넘겨줄 것인지, yyyyMMdd를 넘겨줄 것인지, yyyy-MM-dd hh:mm:ss 등 고민이 생길 것이다.

public PersonalAttendApplications getPersonalAttendApplications(String localDate){..}

public PersonalAttendApplications getPersonalAttendApplications(LocalDate searchDate){..}

그러나 파라미터 타입이 LocalDate라면 데이터 형식에 대한 고민없이 바로 넘겨줄 수 있을 것이다.


3. 적절한 타입의 반환이 필요하다.

단축키(윈도우) : ctrl + B
단축키(맥) : option+command+m


3. 추상화 레벨 동등화

추상화 레벨을 비슷하게 맞출 경우, 코드를 이해하기 쉬워진다.

showGameStartComments();					// 10
initalizeGame(); 							// 10
...

// as-is
if (gameStatus == 1) { 						// 5
    System.out.println("지뢰를 모두 찾았습니다. GAME CLEAR!");
    break;
}

// to-be
if (doesUserWinTheGame()) { 				// 10
    System.out.println("지뢰를 모두 찾았습니다. GAME CLEAR!");
    break;
}

as-is 소스의 경우, gameStatus값이 1인 의미에 대해 추론해야하는 과정이 필요하지만
to-be 소스의 경우, 메서드 이름을 통해 바로 유추 가능하다.


4. 상수 추출

유지보수성을 올라가도록 상수를 추출해보자.
상수명을 짓는 규칙은 다음과 같다.

// 대문자 + 언더바

LAND_MINE_COUNTS

단축키(맥) : option+command+c



논리, 사고의 흐름

불필요한 정보들을 기억한 상태로 다른 코드를 읽어야한다면, 위의 모든 정보들을 알아야 코드 분석이 가능하다.

그래서 이번에는 뇌 메모리를 최대한 적게 쓸 수 있는 방법

즉, 인지적 사고를 적게하는 방법에 알아보고자 한다.


1. early return

위의 주석과 같이 우리는 앞의 조건들을 기억해야 다음 조건들을 생각할 수 있다.

사고체계를 줄일 수 있는 방법이 없을까?

void run(){
	if(a == b){						// a와 b가 같을 때
    	printSame();
    } else if(a > 3){				// a와 b가 같지 않으면서 a가 3보다 클 때
    	printFirstIsBigger();
    }
}

빠르게 return을 해줌으로써 앞의 조건들로부터 자유로워졌다!

void run(){
	if(a == b){						// a와 b가 같을 때
    	printSame();
        return;
    }
    
    if(a > 3){						// a가 3보다 클 때
    	printFirstIsBigger();
    }
}

else 지양을 통해 조건 복잡도를 낮춰주자.


2. 사고의 depth 줄이기

중첩 분기문, 중첩 반복문

중첩 분기문, 중첩 반복문의 depth를 줄일 수 있는 방법은 무엇일까?

for(int i = 0; i < 10; i++){
	for(int j = 0; j < 5; j++){
    	if(i > j){
       		...						// i < 10, j < 5, i > j
        }

주석과 같이 여러 조건들에 대해 인지하고 있어야한다.

메소드 분리를 통해 사고의 depth를 줄일 수 있다.

for(int i = 0; i < 10; i++){
	doSomethingWithI(i);
}

private void doSomethingWithI(int i){
	for(int j = 0; j < 5; j++){
    	doSomethingWithIJ(i, j);
    }
}

private void doSomethingWithIJ(int i, int j){
	if(i > j){
    	doSomething();
    }
}

** 사용할 변수는 가깝게 선언하기

3. 공백

공백을 통해 로직 의미 단위로 나눌 수 있다.


4. 불필요한 부정 연산자 제거

부정 연산자의 경우에도, 사고 로직을 한번 더 거쳐야한다.
긍정을 생각하고 다시 부정으로 변환하는 과정이 필요하기 때문에, 메서드 추상화 방법을 이용하자.

// as-is
if(!(attendApplicationList.size() > 0)){ // (근태 신청서 리스트의 size가 0보다 크다)가 아니다
	...
}

// to-be
if(NoAttendApplicationList){			// 근태 신청서가 없을 때
	...
}

5. 해피케이스와 예외처리

의도된 예외처리를 통해 예외 메세지를 사용자가 볼 수 있도록 처리하자.

profile
차근차근

0개의 댓글