입사하고 첫날 선물 받은 개발자의 바이블
클린코드
8개월 만에 다 봤다.
클린 코드를 보고 유의하고, 기록해야 된다고 생각되는 부분을 정리해봤다. (후반부만)
실제 코드를 짜기 전에 단위 테스트부터 짠다.
- 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
- 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
- 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.
가독성
테스트당 assert문 하나
테스트당 개념 하나
FIRST
static public -> static private -> private
(공개 변수가 필요한 경우는 거의 없다)
클래스는 작아야한다(클래스는 책임으로 카운트)
java.util.concrrent
, java.util.concurrent.atomic
, java.util.concurrent.locks
SPR(Software Problem Reposrt)
번호 등만 설명문법
, 단어
신중히 선택JAR
파일, XML
파일, 기타 시스템에 필요한 파일을 찾느라 뒤적일 필요 없어야 한다svn get mySystem
cd mySystem
ant all
출력 인수가 직관을 정면으로 위배하는 이유
함수의 매개변수 -> 인수
인수의 두 가지 종류
* 입력 인수
* 출력 인수
ex1)
boolean fileExists("Myfile"){
// 생략...
}
ex2)
public void appendFooter(StringBuffer report) {
// 생략...
}
* 함수에서 인수는 두 가지 목적으로 처리
1. 조회 (X(인수) -> f -> Y(boolean; 참 혹은 거짓))
2. 변환 (X(인수) -> f -> Y(다른 객체))
- 리턴 값이 바뀜
ex2) -> 인수 StringBuffer에 report 추가 후
StringBuffer라서 StringBuffer 반환이 필요하지 않음
해결) report.appendFooter();
-> `this` 사용
출처 : [클린코드] 출력인수를 가급적 피하라 ( this의 존재 이유 )
boolean
인수는 함수가 여러 기능을 수행한다는 명백한 증거Day day = DayDate.StringToDay(String dayName);
파생 클래스
가 기초 클래스
의 기능을 받아써야 한다function(…, false)
같은 선택자 인수는 내부를 쪼개야 함static
을 붙이지 말자...
Matcher match = headerPattern.matcher(line);
String key = match.group(1);
String value = match.group(2);
headers.put(key.toLowerCase(), value);
...
**key와 value가 서술적 변수**
Date newDate = date.add(5);
(5주, 5시간, 5일인지 불명확)
->
Date newDate = date.IncreaseByDays(5);
한 모듈이 다른 모듈에 의존한다면 물리적인 의존성도 있어야 한다 (논리적인 의존성으로는 부족)
public class HourlyReporter{
private HourlyReportFormatter formatter;
private List<LineItem> page;
private final int PAGE_SIZE = 55;
...
}
PAGE_SIZE
상수 왜 필요? -> 잘못 지운 책임HourlyReportFormatter
가 페이즈 크기를 알고있다는 논리적 의존성HourlyReportFormatter
내에 getMaxPageSize()
메소드 추가로 물리적 의존성 변환switch
문을 한번만 사용enum
변수가 멋진 switch/case
문보다 더 좋다if(shouldBeDeleted(timer)
if(!buffer.shouldNotCompact())
if (buffer.shouldCompact())
실행되는 순서가 중요한 코드는 연결 소자를 생성해 시간적인 결합을 노출한다
...
public void dive(String reason) {
saturateGradient();
reticulateSplines();
diveForMoog(reason);
}
->
public void dive(String reason) {
Gradient gradient = saturateGradient();
List<Spline> splines = reticulateSplines(gradient);
diveForMoog(splines, reason);
}
if (level + 1 < tags.length) {
parts = new Parse(body, tags, level + 1, offset + endTag);
body = null;
}
* level + 1이 두번 반복
->
int nextLevel = level + 1;
if (nextLevel < tags.length) {
parts = new Parse(body, tags, nextLevel, offset + endTag);
body = null;
}
함수 내 모든 문장은 추상화 수준이 동일해야 한다.
추상화 수준은 함수 이름이 의미하는 작업보다 한 단계만 낮아야 한다
가장 어렵고 리팩토링 수행의 가장 큰 이유
public String render() throws throws Exception {
StringBuffer html = new StringBuffer("<hr");
if(size > 0)
html.append(" size=\"").append(size + 1).append("\"");
html.append(">");
return html.toString();
}
* 수평선 크기가 있다 (나도 모름)
* HR 태그 문법
* 추상화 수준 최소 두개?
->
public String render() throws Excpetion {
HtmlTag hr = new HtmlTag("hr");
if(size > 0)
hr.addAttribute("size", "" + (size+1));
return hr.html();
}
import package.*;
Enum
마음껏 활용솔직히 8개월 동안 밀린 인프런 강의도 많았고, 귀찮다, 바쁘다 등의 핑계로 클린 코드를 미루고 있었다. 근데 얼마 전에 업무 중에 코드 보수하는 과정에서 내 코드에서 허접함이 느껴지고
, 전문성이 떨어져 보인다
는 생각을 하게되었다.진작 클린 코드를 읽었다면...
이라는 생각이 머릿 속에 스쳐갔다. 물론 읽는게 다는 아니지만 어느정도 좋은 코드, 유지보수 용이한 코드를 만들기 위한 노력을 해야된다고 느끼니 클린 코드를 안 읽을 수 없어 열심히 읽었다.
그리고 이전까지만해도 TDD
, 테스트 중심의 코드
에 대해 사람들이 너무 유난이다
, 그 정돈가?
라는 생각이 좀 있었다. 현재 우리 회사는 제품 출시 초기라 테스트보다는 속도와 빠른 적용이 중요한 시기라고 생각하고 테스트에 대한 생각은 미뤘었다. 그런데 1주전 한 코드를 유지보수하다가 다른 부분의 오류가 발생할 수도 있겠다는 생각에 무서웠고, 더 무서운건 내가 짐작할 수 없다는 사실이었다. 그리고 클린 코드를 읽으면서 TDD
와 테스트 코드
가 중요하다는 것을 강조하고, 생각 이상으로 중요하다는 걸 느낀다.
그동안에 개발 방식이 잘못됐을 수도 있지만 개선할 점이 보인다는 것은 긍정적이라 믿고 앞으로 깨끗한 코드와 테스트 주도 개발을 할 수 있도록 노력 + 공부해야겠다.