본문 바로가기
EXTERNAL ACTIVITY/Code Presso -웹개발 트랙 체험단-

<코드 프레소 웹개발 트랙> SW 유지보수성 향상을 위한 Clean Code [2]

by jaeaemin 2022. 1. 22.

 

 

Clean Method

 

  • Metod/Function은 SW에서 가장 기본이 되는 모듈이다.
  • Method를 호출하는 사람이 사용하기 용이해야 한다.
  • Metohd를 유지보수 하는 사람이 이해하고, 변경하기 용이해야 한다.
  • Method를 유지보수 하는 사람이 테스트 하기 용이해야 한다.
  • 유닉스 철학 DOTADIW : Do One Thing and Do it Well

 

Clean Method 원칙

  1. 가능한 한 충분히 작아야 한다.
  2. 한가지를 해야 한다. 그 중 한가지를 잘 해야 한다.
  3. 테스트 가능해야 한다.
  4. 중복이 없어야 한다.

 

 

 

1. Parameter for CleanMethod

 

Parameter의 원칙

  • Method를 호출하는 사람의 인지적 부하를 최소로 만들어 주어야 한다.
  • Method를 호출할 때마다 내부 코드를 보거나 API 문서를 보지 않게끔 해야 한다.
  • Parameter의 개수는 가능한 한 적어야 한다.

 

Parameter의 개수

갯수 평가 예시
0 개 최고의 옵션 product.sava()
1 개 충분히 좋음 isValidEmail(email)
2 개 보통 getDiscountedPrice(price, productType)
// productType 마다 함수를 설정하는건 어떨까?
3 개 개선 가능성 검토 필요 saveUser( email, username, password )
// 파라미터를 객체나 map으로 바꾸면 어떨까? 고민해 볼 수도
4 개 이상 개선 필요 saveUser(email, username, password, gender, .. )

 

Parameter의 개수가 3~4개 이상일 때 방법론 

Method를 분할 예) 계산을 하는 메소드가 아닌 더하기, 뺄셈, 곱셈 등 특정 역할을 하는 메소드 n개로 분할시킨다.
Parameter ovject를 사용 예) Parameter Data를 저장하는 Object를 활용한다. (인자의 순서를 헷갈릴 필요가 없음)
생성자의 경우 Builder pattern을 활용  - Product("cleancode", "course", 19 , "jaemin" , ... )
 -> Product.builder().name("cleancode").type("coures").price(10) ...
Map의 사용
public saveProduct(Map<> p ) 
Parameter 개수가 많을 시 map의 사용이 고려될 수 있음
Map의 Key 값이 유동적이기 때문에 추가적인 문서화 필요
Map의 Key의 정보나 개수가 변경 되었을 시 알기 어려움
호출하는 사람이 key값에 오타를 입력하는 겨웅 에러 발생 

 

 

 

 

2. Method size for Clean Code

 

작고 역할이 명확한 메소드의 장점

  • 기존 코드를 수정하기 용이하고, 단위 테스트하기 용이하다.
  • 일고 이해하기 쉽다.
  • 재사용성이 높다.

 

적절한 Method의 크기는 ?

Clean Code 저자 - 100라인을 넘어서는 절대 안되 안되고, 20라인을 넘는 경우도 거의 없어야 한다.
- 모든 함수가 2줄-4줄 정도였고, 각 함수가 너무 명백했다.
- 각 함수가 이야기 하나를 표현하고 바로 그것이 답이다.
Refactoring in Large - Method 들의 평균 라인 수는 30라인이 넘어서는 안된다.
Code Complete 저자 - 한 화면 안에 들어가는 라인 수가 최대 라인 수다.
- 연구에 따르면 Method는 65라인 ~ 200라인 안쪽에서 가장 에러가 적었다.

 

하지만, 크기(라인 수)만으로 Method의 품질을 판단 할 수는 없다.

 

Kent Back's Four Simple Design Rulses

  1. 모든 테스트가 실행해야 한다.
  2. 중복을 없애야 한다.
  3. 프로그래머의 의도를 잘 설명해야 한다.
  4. 클래스와 메소드의 크기를 최소한으로 유지한다.

 

Rule of Thumb - Method의 크기

  • 10 ~ 100 라인 사이가 적절, 그러나 숫자에 집착할 필요는 없다.
  • 1개의 Method는 스크롤링 하지 않고 읽을 수 있어야 한다.
  • 단위 테스트 케이스를 작성하는 데 어려움이 없어야 한다.
  • Method의 동작을 설명하기 위해 내부 주석을 달아야 하면 Bad Smell
    • 주석이 필요한 코드들은 새로운 Method로 추출하자 

 

 

 

한가지의 명확한 일을 하는 Method 란 

  • 명확한 Naming이 가능하고, 이름만으로 기능을 이해할 수 있다.
  • 복잡도가 낮아질 가능성이 높음 ( Cyclomatic Complexity )
    • 조건문의 복잡한 중첩구조가 적다
  • Method의 내부 코드를 이해하고 수정하기 용이하다
  • 단위테스트 하기 용이하다

 

그러면 여기서 Method의 한가지 일이란 무엇일까

한 가지의 일을 한다는 것이 정확한 어떠한 의미일까 라인수? 역할? 

아래의 코드를 보고 이 코드는 몇개의 일을 한다고 할 수 있을까

5가지? 1가지? 

 

 

여기서 우리는 가이드라인을 제시할 수 있다. 

" 하나의 Method는 동일한 추상화의 수준만 가져야 한다. "

추상화의 수준(Level of Abstraction) 이란 ?

추상화의 수준 예시 ( Level of Abstraction )
High Level Intermediate Level Low Levle Lower Level
- 회원 가입 - 사용자 정보 저장
- 이베일 발송
- 쿠폰 발행
- 이메일 포맷 검증
- 이메일 중복 검증
- 패스워드 검증
-이메일에 @ 캐릭터 체크
- 패스워드가 5~10글자 체크 

 

좋은 추상화의 예시 ( 회원 가입 - 사용자 정보 저장, 이메일 발송 , 쿠폰 발행 )

- 추상화의 레벨만 들어가서, 이메일 체크, 유저 저장, 등의  다른 추상화 레벨 역할이 없음 

public signUp(email, password) {
	
    saveUser(email, password);
    
    sendWelcomeEmail(email);
    
    issueCoupon(user);
    
    return ...;
}

 

 

나쁜 추상화의 예시 ( 다른 레벨의 추상화 목적 코드가 섞인 경우 )

 

이를 동일한 추상화 수준을 가져가는 코드로 통일하여 Method를 작성하는 경우 어떻게 될까?

public void saveUser (email, password) throw UserException {
    vaildateEmailFormat(email);
    validateEmailDuplication(email);
    validatePassword(password);
    
    User user = new User(email, password);
    
    user.save();
}

private validateEmailFormat(email) throw UserException {
	if(!emial.contatins("@") || !email.contains(".") {
    	throw new UserException(...)
    }
}

private validateEmailDuplication(email) ...

 

2번째 가이드라인은 다음과 같다.

" Method의 이름이 책임지는 범위의 일만 해야 한다."

(옳은 예시) 책임의 범위는 개인별/조직별 정책에 따라 달라진다.

 

[Bad smell]  (나쁜 예시) 함수의 이름이 기능과 그 책임을 무시하는 경우

 

모든 메소드를 처음부터 잘 설계하고 개발하는 것은 쉽지 않다. 이를 위해서 지속적인 개선이 필요하다.

  1. 조직 내 컨센서스를 만들어 나가야 한다.
    1. 코드 리뷰를 통해 메소드를 지속적으로 리뷰하고 개선해야함 
  2. 충분히 작은가? 충분히 테스트 되고 있는가? 끊임없이 질문과 개선이 중요하다.
  3. 처음부터 거대한 Method는 적음
    1. 설계 고려 없이 기존 Method에 기능을 추가하는 것은 위험하다.

 

 

 

 

3. 중복 코드란?

 

  • 일정 라인 수 이상이 다수 중복되어 존재하는 코드
  • 개발자는 복사/붙여넣기의 유혹과 갈등하는 경우가 존재함.
  • 기존 메서드/클래스를 수정하기 두려운데 복사/붙여넣기 해서 조금만 수정할까?
  • 중복 코드는 다양한 문제점을 발생 시킨다.

 

중복 코드의 종류
Method 전체 코드 중복 다수의 Method의 구현부가 100% 일치
Method의 이름은 다를 수 있음
연속된 일련의 코드 중복 Method 전체는 아니지만 일부 연속 된 코드가 다수 중복 됨
중복 코드의 대다수를 차지하는 유형 
일부만 다른 코드 중복 코드의 중복이 있지만, 중간 1-2 라인 정도만 다른 경우
Refactoring하기 가장 까다로운 유형 

 

 

중복 코드의 문제점은 무엇일까?

  • 불필요하게 코드 베이스를 크게 만듬 => 유지보수성을 떨어 뜨림
  • 코드를 수정할 때 중복 된 다수 코드를 모두 수정해야 함 => 일부 누락 시 에러 발생
  • 중복 코드의 잠재적 결함이 존재하면, 결함도 게속 중복 된다.

 

중복 코드를 발견하는 방법

  • 지속적인 코드 리뷰 
    • 수동으로 전체 SW 시스템의 중복을 다 발견하기 쉽지 않다.
  • 정적 분석을 사용한다.
    • 정적 분석 도구 - CPD, Atomiq

 

중복 코드의 해결 방법 

: 다양한 Refactoring 전략 및 Design pattern 적용

  • Extract Method
    • 중복된 코드를 새로운 Method로 추출 
  • Extract Superclass
    • 서로 다른 클래스에 코드가 중복되는 경우 사용
    • 중복 코드를 부모 클래스에 위치시켜 기존 클래스들은 해당 클래스를 상속
  • Template Method Pattern
    • 알고리즘의 일부가 중복되는 경우 사용한다.
    • 공통 알고리즘을 정의하고, 일부 알고리즘에 대해 오버라이딩 하여 사용

 

 

4. 깨진 유리창 이론

 

SW Aging이란?

SW가 오래 유지보수 되어 기술 부채가 늘어난 경우 코드/아키텍처 품질이 저하되고, 게속되는 요구사항으로 실제 SW와 문서 간의 차이가 발생한다. 이 경우 유지보수에 비용이 너무 많이 들어가 SW를 완전 재개발 해야 되는 상황이 발생된다.

 

깨진 유리창 이론 

  • 깨진 유리창을 방치하면 그 장소를 중심으로 범죄가 확산 된다.
  • 사소한 문제를 방치하면 빠르게 큰 문제로 변질될 가능성이 크다.

 

깨진 유리창 이론과 중복 코드

  • doSomethong이라는 Method가 존재하고, 이 Method 기능을 수정해야 함.
  • 테스트 코드도 없는 상태에서 기존 Method를 수정하기 두려움
  • 복사, 붙여넣기 하여 일부만 수정할까 갈등하는 도중 doSomething2를 발견 
  • doSomething3를 만드는데 마음의 장벽이 허물어짐 

 

깨진 유리창 이론과 Long Method

  • 작고 명확하게 한 가지 일을 하는 Method는 수정할 때도 더 신경 쓰게 된다.
  • 그러나 200라인 Method에 10라인 추가하는 것은 죄책감이 들지 않음. (깨진 유리창)

 

즉, 깨진 창문이 일정 수준이상 진행된 코드에서는 개발자들은 자포자기 하는 경우가 많다.

따라서 창문을 깨지지 않게, 깨진 창문도 정상화는 조직 차원의 문화가 형성 되어야 한다.

- 코드 품질의 컨센서스 , 코드 리뷰, 정적 분석, 테스트 커버리지 등을 확인해야함

- 지속적인 SW 품질 향상에 대한 노력이 가장 중요하다.

 

 

 

 

5.  보이스카우트 법칙

 

보이스카우트 법칙이란?

  • 캠프장에 처음 왔을 때보다 더 깨끗하게 해놓고 떠나라
  • 체크아웃 할 때보다 조금이라도 더 깨끗한 코드를 체크인 하라
  • 아주 작은 개선이라도 지속 되면 코드는 나빠지지 않는다.
    • 함수 분할, 중복 코드 제거, 중첩 If 정리 ...

 

보이스카우트 규칙의 전제

  • Clean Code를 장려하는 문화 
    • code를 개선하려는 노력을 무시해서는 안된다. (유지보수성의 나쁜 영향)
  • 단위 테스트 코드의 존재  "필수적 "
    • 수정 후 기존 기능에 영향이 없는지 검증이 꼭 필요함
    • 개발자가 수동으로 테스트 하는 것에는 한계가 있음
    • 수정 후 테스트 코드를 실행하여 문제가 없음을 꼭 확인 해야함

 

지속적인 코드 개선의 걸림돌

  • 엔지니어는 자신의 코드에 자신의 자아를 투영하는 경향이 있음
  • 자신이 작성한 코드에 과도한 애착 + 방어적 태도의 존재
  • 자신의 코드를 리뷰받고 피드백 하는 것에 대한 거부감
  • 자신의 코드를 다른 사람이 수정하는 것에 대한 거부감

 

비자아적 프로그래밍 (Egoless Programming)

  • 엔지니어 개개인의 요소들을 최대한 제거함으로써 전체 SW 품질을 높이는 문화
  • 각자 만든 코드에 개개인 자아를 투영하지 말아야 함
  • 코드에 대한 공동 소유, 공동 책임 철학을 강조해야 한다 
  • 프로젝트 초기부터 지속적인 코드 리뷰 또는 페어 프로그래밍으로 달성 가능
  • 비자아적 프로그래밍의 가이드 : 
    • 당신이 실수 할 수 있다는 것을 받아 들여라
    • 당신과 당신이 작성한 코드는 다르다
    • 당신보다 지식이 적은 사람이라도 존중하고 인내를 갖고 대하라
    • 세상에 고정되어 있는 것은 없다. 변화를 받아 들여라
    • 사람이 아닌 코드를 비판하고, 사람에게는 친절히 대하라 

 

 

6. Method 측정 지표

 

[1] Lines Of Code

  • Method의 길이를 측정
  • 조직에서 Bad Smell의 기준을 정하고 이를 넘는 Method 검출
  • 기존 시스템의 Method들 LOC의 평균/표준편차 등을 측정한 후 Outlier 검출

 

[2] Cyclomatic Complexity

  • Method 내부의 복잡도를 측정 하는 지표
  • Method 내부의 조건문 중첩이 복잡할 수록 높아짐
  • CC가 높을 수록 테스트가 어렵고, 수정이 어려움
    • < 10 권장
    • 11-20 유지보수 어렵고, 21+는 Refactoring 고려해야 함

 

 


Clean Method 

  • Method 호출자가 사용하기 용이
  • Method 유지보수자가 이해하고, 변경, 테스트하기 용이해야 한다.
  • 이를 위해 가능한 한 작고, 테스트 가능하고 , DOTADIW가 잘 지켜져야 한다.
  • 적은 파라미터, 명확한 이름과 역할, 중복이 없고, 높은 테스트 용이성이 중요하다.
  • 클린 메소드를 위해선 모든 동료들이 함께하는 코드  품질 개선 문화가 필요함

 

 



- 코드프레소  Java  웹  개발  체험단  활동  중    
- 코드프레소  웹개발 트랙의 "SW유지보수성 향상을 위한 Clean Code" 내용입니다.
- 코드프레소  URL: https://www.codepresso.kr/ 

반응형