본문 바로가기

IT/클린코드

클린코드 15장 JUnit , 16장 SerialDate 리펙터링, 17장 휴리스틱

안녕하세요 남갯입니다.

 

오늘은 클린코드 15,16,17장에 대해 정리해보려고합니다.

 

JUnit

- JUnit은 저자가 많은 자바 테스트 프레임워크이다. 시작은 에릭감마와 켄트백이 만들었다.

- 모듈을 작성시 보이스카우트 규칙을 따른다

* 보이스카우트 규칙이란?

떠날때는 찾을때보다 캠프장을 더 깨끗하게 떠나라

다시 찾아올 수 있는 사람에게 더 수월한 환경을 만들어준다는 뜻.

- 테스트코드 혹은 코드 작성시 의도를 명확히 표현하려면 조건물을 캡슐화해라(메서드로 뽑아 적절하게 이름을 붙여라)

if (expected == null || actual == null || areStringsEqual())
  return Assert.format(message, expected, actual);

이런식으로

if (shouldNotCompact())
return Assert.format(message, expected, actual);

 

- 코드의 변수에도 명확한 이름을 붙여라

String expected = compactString(this.expected);
String actual = compactString(this.actual);

 

String compactExpected = compactString(expected);
String compactActual = compactString(actual);

- 부정문 대신 긍정문을 통해 if문 즉 조건문을 반전하라.

private boolean shouldNotCompact() {
return expected == null || actual == null || areStringsEqual();
}

 

private boolean canBeCompacted() {
return expected != null && actual != null && SareStringsEquaK);
}

 

- 함수의 사용방식을 일관적으로 만들어라. (마지막 두 함수는 반환하고 첫째,둘째줄에는 반환이 없으므로)

동일하게 수정

private void compactExpectedAndActual() {
	findCommonPrefix();
	findCommonSuffix();
	compactExpected = compactSt ring(expected);
	compactActual = compactString(actual);
}

 

private void compactExpectedAndActual() {
	prefixlndex = findCommonPrefix();
	suffixlndex = findCommonSuffix();
	compactExpected = compactString(expected);
	compactActual = compactString(actual);
}

 

- 숨겨진 커플링 제거

prefixIndex와 suffixIndex의 순서가 중요했으므로 순서가 잘못될경우 에러발생

따라서 prefixIndex를 suffixIndex함수의 인자로 전달

 

1차 개선

private void compactExpectedAndActual() {
	prefixlndex = findCommonPrefix();
	suffixlndex = findCommonSuffix(prefixlndex);
	compactExpected = compactString(expected);
	compactActual = compactString(actual);
}

 

2차개선

findComminPrefixAndSuffix() 함수로 위 두가지의 동작을 묶었다.

 

 

결론

이러한개선?을 통해 리펙터링을 했고(리펙토링을 하게되면 처음의 결정을 번복한다.)

보이스카우트 규칙도 지키게된 케이스이다.

 

이 단원은 JUnit을 들여다 보자는 단원이였는데, 점진적인 개선과 거의 비슷한 단원 같았다.

 

 

SerialDate 리펙터링

 

날짜를 표현하는 자바클래스

- JCommon 라이브러리 속 SerialDate 클래스가 있다.

- Calendar와 Date 클래스가 있는데 왜쓰는것일까?

- 테스트 코드가 있었지만 버그가 있었다.

 

- SerialDate라는 이름이 너무 추상적이라 -> Date (많음)-> Day(많음) -> DayDate로 쓰기로 결정

- Constan의 상수모음 말고 상수 클래스를 사용해라.

 

public static enum Month {
JANUARY(l),
FEBRUARY(2),
MARCH(3),
APRIL(4),
MAY(5),
JUNE(6),
JULY(7) ,
AUGUST(8),
SEPTEMBERS(9),
OCTOBER(10),
NOVEMBER(11),
DECEMBER (12);
	Month(int index) {
		this.index = index;
	}
}

 

- 기존 라이브러리에서는 기반클래스가 자식클래스를 몰라야하는데 아는 문제가 있었다. 따라서 추상팩토리 패턴을 적용했다.

 

2019/05/09 - [IT/개발스터디 디자인패턴] - [디자인패턴] 팩토리패턴

 

결론

결국 로버트마틴이 한일

1. 오래된 주석을 간단하게 고치고 개선했다.

2. enum을 모두 독자적인 소스파일(.java) 파일로 옮겼다.

3. 정적변수 (Constant로 만든것들), 정적 메서드를 DateUtil이라는 새 클래스로 옮겼다.

4. 일부 추상 메서드를 DayDate클래스로 옮김

5. Month.make라는 추상적인 의미를 Month.FromInt 로 변경, 또한 즉 Enum에 숫자를 통해 표현했으므로 Enum에 ToInt 접근자를 생성했다.

6. 중복을 없앴다.

7. 숫자 1로 사용하던 January, SunDay 등을 enum 으로 변경

 

그 후에는 클래스의 크기를 변경하면서 커버리지가 증가했다.

 

 

 

 

냄새와 휴리스틱

*휴리스틱(heuristics) 또는 발견법(發見法)이란 불충분한 시간이나 정보로 인하여 합리적인 판단을 할 수 없거나, 체계적이면서 합리적인 판단이 굳이 필요하지 않은 상황에서 사람들이 빠르게 사용할 수 있는 어림짐작의 방법이다.

 

마틴 파울러의 Refactoring 에서 코드냄새라는 것을 거론한다.

 

*리펙토링이란? 외부동작을 바꾸지 않으면서 내부 구조를 개선하는 방법

*위키백과 : 컴퓨터 프로그래밍 코드에서 심오한 문제를 일으킬 가능성이 있는 프로그램 소스 코드의 증상을 가리킨다.

 

 

https://okky.kr/article/58693 

 

OKKY | [마틴파울러]Refactoring에서 나온 좋은 문구

1. 새로운 기능을 추가해야 하는데 프로그램의 코드가 새로운 기능을 추가하기 쉽도록 구조화 되어 있지 않은 경우에는 먼저 리팩토링을 해서 프로그램에 기능을 추가하기 쉽게 하고, 그 다음에 기 능을 추가한다. 2. 리팩토링을 시작하기 전에 견고한 테스트 셋을 가지고 있는지 확인하라. 이 테스트는 자제 검사 여야 한다.

okky.kr

 

주석

 

부적절한 정보 : 소스 관리시스템, 이슈추적 등 은 주석으로 적절하지 못하다. 작성자, 최종수정일, 문제번호 등만 메타주석으로 넣는다.

쓸모 없는 주석 : 오래된 주석, 엉뚱한 주석, 잘못된 주석은 쓸모 없음. 즉 쓸모없어질 주석은 아예 안다는것이 낫다.

중복된 주석 : 코드만으로 설명이 가능함에도 불구하고 구구절절 설명하는 주석이 중복된 주석이다.

성의 없는 주석 : 잘 작성 하기 위해 시간을 들여서 멋지게 작성하고 신중한 단어를 통해 작성하자. 쓸데없는소리 x

주석 처리된 코드: 주석처리된 코드는 오래된 코드인지 중요한 코드인지 알길이 없으므로 주석으로 처리된 코드는 흉물이다.

 

 

환경

여러단계로 빌드해야한다. : 빌드는 한단계로 소스관리시스템에서 이것저것 체크아웃을 안하도록 한번의 명령으로 가능하도록 해야한다.

여러단계로 테스트해야한다. : 모든 단위테스트는 한 명령으로 즉 IDE에서 버튼하나로 모든 테스트를 돌리도록 해야한다.

 

함수

너무 많은 인수 : 인수의 개수는 작을수록 좋다.

출력인수: 일반적으로 독자는 인수를 입력으로 간주

플래그인수: 플래그 인수는 혼란이 있으므로 최대한 피해라.

죽은함수 : 아무도 호출하지 않는 함수는 삭제해라

 

일반

한 소스 파일에 여러 언어사용 : 혼란스럽거나 조잡해진다 한개만 써라

 

당연한 동작을 구현하지 않는다. : 즉 문자열을 enum으로 바꾸는 쓸데없는 동작을 만들지 않음

 

경계를 올바로 처리하지 않는다. : 경계 조건을 테스트하는 테스트 케이스를 처리해라.

 

안전절차 무시: 컴파일러의 경고에 맞춰 안전을 지키자

 

중복 : DRY : Don't Repeat YourSelf, Once and Only Once 한번 단 한번만, 등 중복을 발견하면 추상화할 기회로 간주하고 중복된 루틴과 클래스를 분리하라.

 

추상화 수준이 올바르지 못하다. : 추상화 할 때 저차원 개념은 파생클래스에 넣고 고차원 개념은 기초클래스에 넣어라.

 

기초클래스가 파생클래스에 의존한다. : 파생클래스는 기초클래스를 아예 몰라야 한다.

 

과도한 정보: 인터페이스를 분리해라 (ISP) 

 

죽은 코드 : 죽은 함수와 동일하게 실행하지 않는 코드

 

수직 분리: 최대한 사용하는 위치에 가깝게 정의

 

일관성 부족: 특정방식을 통해 구현하면 유사한 개념도 비슷한 방식으로 구현하라.

 

잡동사니 : 빈 기본생성자 지워라(잡동사니를 지워라)

 

인위적 결합 : 서로 무관한 개념은 결합하지 말아라 (enum은 특정 클래스에 속할 필요 없음)

 

기능욕심 : 클래스 메서드는 자기의 클래스 변수와 함수에만 관심을 가져라

 

선택자 인수: 인수를 넘겨 동작을 선택하는것보다 새로운 함수를 만들어라.

 

모호한 의도 : 코드를 짤때는 의도를 명확하게 밝혀라

 

잘못 지운 책임: 코드는 독자가 자연스럽게 기대할 위치에 배치해야한다.

 

부적절한 static 함수 : static 함수보다 인스턴스 함수가 더 좋으므로 의심된다면 인스턴스 함수로 정의해라.

 

서술적변수 : 계산을 여러단계로 나누고 중간값으로 서술적인 변수를 사용해라.

 

이름과 기능이 일치하는 함수 : Date.add 보단 addDaysTo라는 이름이 낫다.

 

알고리즘을 이해하라 : 기능이 뻔히 보이도록 함수를 깔끔하게 짜라

 

논리적 의존성은 물리적으로 드러내라. : 책임질 정보를 당연히 알거라고 생각하는 가정자제

 

if/else 혹은 switch case보다 다형성을 이용하라. : 다형성 객체를 생성해 switch문 대신

 

표준 표기법을 따라라. : 컨벤션을 따라라

 

매직 숫자는 명명된 상수로 교체 : 특정 숫자로 교체해라

 

정확하라 : 통화를 사용한다면 정수를 사용하는것과 같이 기본적으로 사용

 

관례보다는 구조를 사용하라. 추상클래스로 필요한것을 강제

 

조건을 캡슐화하라 : 

if (shouldBeDeleted(timer))  보단
if (timer.hasExpired() && !timer.isRecurrent())

 

부정조건을 피하라. 

함수는 한가지만 해라 . 

 

숨겨진 시각적인 결합: 호출 순서대로 배치

 

일관성을 유지하라 : 이름과 코드를 일관적으로 짜라

 

경계조건을 캡슐화 하라 : +1를 흩어 놓지 않는다.

 

함수의 추상화수준을 한 단계만 내려가야한다.

 

설정정보는 최상위 단계에 둬라 : 상수의 설정정보 등은 최상위에 둬라

 

추이적 탐색을 피하라 : 모듈은 주변 모듈을 모를수록 좋다.

 

자바

import 긴 목록 피하고 wild card 사용하라

상수는 상속하지 않는다.

상수 vs Enum  enum 써라

 

이름

서술적인 이름써라

적절한 추상화수준에서의 이름 선택해라

표준명명법을 써라 (패턴쓸경우 패턴이름 뒤에붙이는형태)

명확한이름

긴번위는 긴이름을 사용해라

인코딩을 피하라

이름으로 부수효과를 설명하라.

 

테스트

불충분한 테스트

커버리지 도구

테스트 건너뛰지 마라

무시한 테스트는 모호함이다.

경계조건을 테스트하라.

버그 주변은 철저히 테스트해라

실패케이스를 만들어라

테스트 커버지지 패턴을 살펴라

빠르게 테스트 해야한다.

 

'IT > 클린코드' 카테고리의 다른 글

[클린코드] 7장 오류처리  (0) 2020.02.05
[클린코드] 6장 객체와 자료구조  (0) 2020.02.04
[클린코드] 5장 형식  (0) 2020.02.03
[클린코드] 4장 주석  (0) 2020.01.29
[클린코드] 3장 함수  (0) 2020.01.28