일상

클린코드(Clean code) 리뷰

  • -
반응형

어느새 개발자로 일을 시작한지 4년에 접어들었다. 요즘 부쩍 고민이 많다.

 

최근에 스타트업으로 이직을 하면서 서버 REST API 개발과 프론트 개발을 겸하고 있다. 거기에 배포 환경 구축, DB 설계, 운영 서버 환경도 셋팅하고 할 일이 참 많아졌다. 다양한 경험을 할 수 있어 좋은 점도 있지만 사수없이 모든 것을 하려니 조금 걱정이 된다.

 

지금까지 배운 것들과 구글링을 하면서 해나가고 있지만 아직은 좀 더 경험이 많은 사수에게 배울 시기가 아닐까라는 생각이 든다. 그래서 책을 많이 읽으려고 한다. 책으로라도 간접 경험을 하려고.

 

이 책을 읽은 이유는 현재 진행 중인 프로젝트에서 개발자간의 규칙을 정하는데 있어 기준이 되는 무언가가 필요해서였다. 클린코드에 대한 비판도 있었지만 나는 이 책이 추구하는 본질은 좋은 프로그램을 만들고, 코드 한 줄에 고민하는 모습이라고 생각했다.

 

책을 읽으며 공감이 가는 문장과 다짐하게 되는 것들이 있었다. 그 몇가지를 공유해볼까 한다.

 

첫번째, 독자의 입장을 생각하자.

언젠가 okky에서 "개발자는 본인이 작성한 코드의 저자이다. Java에서 주석의 author는 독자가 있다는 의미다."라는 비슷한 맥락의 말을 본 적이 있었다. 그 후로 나는 코드를 작성할 때 이 코드를 읽을 누군가를 위해 고민했었다. 효율적이면 더 좋겠지만 그렇지 못하더라도 가독성이 좋게 작성하려고 했다.

그리고 책의 첫 장에서 바로 이런 문장을 접했다. "javadoc에서 주석- author는 저자를 의미한다. 저자에게는 독자와 잘 소통할 책임이 있다." 

"아 누군가가 이 책을 읽고 썼구나" 생각했다. 그리고 책을 사길 잘했다는 생각이 들었다.

 

두번째, 변수와 함수를 만들 때 의도가 드러나도록 이름을 사용하자.

나는 종종 변수와 함수를 의미있게 만들지 못했던 것 같다.

가령 이런 것이다. 사실 크게 문제가 되는 코드는 아니지만 map의 이름을 좀 더 의미있게 사용할 수 있었을 것 같다.

Map<String, Object> map = userService.getUserInfo(userid);

String username = (String) map.get("username");
String usermobile = (String) map.get("usermobile");
Map<String, Object> userMap = userService.getUserInfo(userid);

String username = (String) userMap.get("username");
String usermobile = (String) userMap.get("usermobile");

 

세번째, 함수의 크기를 줄이자.

내 경험에 비추어볼 때 함수에서 들여쓰기 수준이 1,2단을 넘어가기 시작하면 함수를 읽고 쓰기가 어려웠던 것 같다. 그런 점에서 이 말도 나에게 설득력 있는 주장이었다. 또 함수의 크기가 커질수록 부수적인 주석이 많아졌던 것 같다. 아마도 코드를 읽을 다음 사람을 위해서였겠지만 저자는 이야기하기를 긴 주석보다 서술적인 이름을 사용한 함수로 표현하라고 한다. 긴 주석이 작성된 코드를 의미있는 함수로 만들어 표현하라는 것으로 받아들였다. 그리고 함수의 인수로 사용되는 Boolean 값은 추하다고 표현할 정도로 최악이라고 했다. 함수가 여러 가지 기능을 처리한다는 것을 의미하기 때문이었다. 아마도 이런 경우가 아닐까. 

저자는 항상 강조한다. 함수는 하나의 기능만 해야한다고.

...
{
	isRegisted(true);
}

public void isRegisted(boolean checkVal) {
  if (checkVal) {
   	updateUser();
  } else {
   	insertUser();
  }
}

 

네번째, 주석은 필요악이다.

저자는 주석에 대해 비판적인 태도를 보였다. 주석은 오래될수록 코드에서 멀어지며 주석을 유지보수하기란 현실적으로 불가능하다라는 근거였다. 공감한다. 코드가 점점 오래될수록 주석은 신뢰가 떨어졌다. 나또한 그랬다.

나같은 경우는 공통 클래스의 경우 이력을 기록하는 주석을 항상 달아놓는 편이었는데 이 책에서는 이력을 기록하는 주석을 완전히 제거하는 편이 낫다는 의견이었다.

/**
 * 
 * @author user
 * <pre>
 * 수정일      작성자  작업내용
 * ----------  -----   --------------
 * 2021.12.31  LSH     모듈 로직 수정
 * </pre>
 */

예전에는 소스 관리 시스템이 없었기 때문에 이력 관리를 위한 주석이 바람직했으나 요즘에는 그렇지 않기 때문이라고 했다. 맞는 말이라고 생각했고 앞으로는 최종 수정일 정도만 기록해두려고 한다.(그래도 마지막 기록만 남겨두고 싶어서..)

그리고 주석으로 처리한 코드에 대해 언급했다. 이 부분이 사실 가장 공감이 가는 대목이었는데 지금까지 일하며 접한 코드에는 항상 주석으로 처리된 코드를 발견할 수 있었다. 보고싶지 않아도 볼 수 밖에 없고 지우고 싶어도 이유가 있을 것이라는 염려 때문에 지울 수 없는 코드. 하지만 저자는 이런 코드를 지우기를 권장한다. 이 역시도 소스 관리 시스템이 있기 때문에.

 

다섯번째, 사소한 어떤 것들.

아무리 열심히 개발을 해도 인계 받는 사람에게 욕먹지 않는 코드는 만들기 힘들다라는 말을 많이 들었다. 그럼에도 불구하고 내가 작성한 코드를 누군가 읽었을 때, 저자가 말하는 질서 정연하고 깔끔하다 정도의 코드가 되기를 바란다.

저자는 변수 선언은 사용하는 위치에 최대한 가까이 선언하라고 한다. 한 함수가 다른 함수를 호출한다면 두 함수 또한 가까이 배치하라고 한다. 이를 신문 기사에 비유했다. 위에서 아래로. 고차원에서 저차원으로. 요약된 것에서 구체적인 것으로.

 

여섯번째, 때로는 단순하게.

때로는 단순한 자료 구조와 절차적인 코드가 적합한 상황이 있다. 절차지향적인 코드는 기존 자료 구조를 변경하지 않으면서 함수를 새로 추가하기 쉽다. 그리고 객체지향적인 코드는 기존 함수를 변경하지 않으면서 새 클래스를 추가하기 쉽다.

 

일곱번째, 예외를 활용하자.

Null 확인을 하기보다는 예외를 던지라고 한다. 아래와 같은 경우를 null 확인을 어디서라도 빼먹으면 통제가 안된다. 

public void registedUser(UserDTO userDTO) {
    if (userDTO != null) {
    	String userid = (String) userDTO.getUserid();
        if (userid != null) {
      		Map<String, Object> userMap = userService.selectUserInfo(userid);
            if (userMap != null) {
            	...
            
            }
        }
    } 
}

 

여덟번째, 테스트의 중요성

여러 가지 기능보다는 한 가지 기능의 테스트 함수를 만들자. 또 어떤 순서로 실행해도 문제가 없어야 한다. 저자가 강조한 테스트는 다음과 같았다.

테스트는 빨라야 한다.

테스트는 환경에 구애 받지 않아야 한다.(네트워크가 연결되지 않은 상황일지라도)

테스트는 true/false로 결과를 내야 한다.

테스트는 실제 코드를 구현하기 직전에 만든다.

 

마지막, 좋은 클래스를 만들자.

저자는 좋은 코드를 작성하기 위해 좋은 클래스를 만드는 법에 대해 설명한다. 우리가 SRP(단일책임원칙)를 지키지 못하는 이유는 뭘까. 수많은 책임을 떠안는 클래스들을 꾸준하게 접한다. 이유는 돌아가는 소프트웨어에 초점을 맞추기 때문이다. 나 또한 그렇다.

저자가 강조하는 부분은 큰 클래스 몇 개가 아닌 작은 클래스 여러 개가 더 바람직한 시스템이라는 것이다.

 

이외에도 좋은 내용이 매우 많았다. 그 중 가장 기억에 남는 것들을 메모했었고 위의 내용이 그것이다.

 

결국 저자는 좋은 함수를 만들기 위해서는 서투르고 어수선한 초안을 다듬어 가는 방법 밖에 없다고 한다. 처음부터 잘 만들면 좋겠지만. 내 생각에 클린코드의 시작은 들여쓰기가 아닐까 생각한다. 들여쓰기는 코드를 정리하고 구분해주는 능력이 있다. 들여쓰기가 없는 코드는 정말 생각만해도 끔찍하다. ^^;

반응형
Contents

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

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