읽기 좋은 코드가 좋은 코드다(더스팀 보즈웰, 트레버 파우커 지음, 임백준 옮김) 를 읽고 자주 참고하면서 습관화하려는 부분을 정리해 놓은 것으로 좀 더 자세한 내용은 책을 보기 바랍니다. |
point. 좋은 소스코드는 '눈을 편하게' 해야 한다.
- 읽기 편한 소스코드를 작성하는 세 가지 원리
- 코드를 읽는 사람이 이미 친숙한, 일관성 있는 레이아웃을 사용하라.
- 비슷한 코드는 서로 비슷해 보이게 만들어라.
- 서로 연관된 코드는 하나의 블록으로 묶어라.
일관성과 간결성을 위해서 줄 바꿈을 재정렬하기
|
before
public class PerformanceTester {
public static final TcpConnectionSimulator wifi = new TcpConnectionSimulator(
500, // Kbps
80, // millisecs 대기시간
200, // 흔들림
1 // 패킷 손실
);
public static final TcpConnectionSimulator t3_fiber =
new TcpConnectionSimulator(
500, // Kbps
80, // millisecs 대기시간
200, // 흔들림
1 // 패킷 손실
);
public static final TcpConnectionSimulator wifi = new TcpConnectionSimulator(
500, // Kbps
80, // millisecs 대기시간
200, // 흔들림
1 // 패킷 손실
);
}
after
public class PerformanceTester {
public static final TcpConnectionSimulator wifi =
new TcpConnectionSimulator(
500, // Kbps
80, // millisecs 대기시간
200, // 흔들림
1 // 패킷 손실
);
public static final TcpConnectionSimulator t3_fiber =
new TcpConnectionSimulator(
500, // Kbps
80, // millisecs 대기시간
200, // 흔들림
1 // 패킷 손실
);
public static final TcpConnectionSimulator wifi =
new TcpConnectionSimulator(
500, // Kbps
80, // millisecs 대기시간
200, // 흔들림
1 // 패킷 손실
);
}
public class PerfoemanceTester {
// TcpConnectionSimulator (처리량, 지연속도, 흔들림, 패킷 손실)
// [Kbps] [ms] [ms] [percent]
public static final TcpConnectionSimulator wifi =
new TcpConnectionSimulator(500, 80, 20, 1);
public static final TcpConnectionSimulator t3_fiber =
new TcpConnectionSimulator(45000, 0, 0, 0);
public static final TcpConnectionSimulator cell =
new TcpConnectionSimulator(100, 400, 250, 5);
before
DatabaseConnection database_connection;
string error
assert(ExpandFullName(database_connection, "Donug Adams", &error)
== "Mr, Douglas Adms");
assert(error == "");
assert(ExpandFullName(database_connection, "Jake Brown", &error)
== "Mr, Jacob Brown III");
assert(error == "");
assert(ExpandFullName(database_connection, "No Such Guy", &error) == "");
assert(error == "no match found");
assert(ExpandFullName(database_connection, "John", &error) == "");
assert(error == "more than one result");
afrer
- 중복된 코드를 없애서 코드를 더 간결하게 한다.
- 이름이나 에러 문자열 같은 테스트의 중요 부분들이 한 눈에 보이게 모아졌다. 수정 전에는 database_connection이나 error 같은 토큰들과 섞인 채 흩어져 있었기 때문에 코드를 한 눈에 파악하기 어려웠다.
- 새로운 테스트 추가가 훨씬 쉬워졌다.
void CheckFullNAme(string partial_name,
string expected_full_name,
string expected_error) {
// database_connection은 이제 클래스 맴버이다.
string error;
string full_name = ExpandFullName(database_connection, partial_name, &error);
assert(error == expected_error);
assert(full_name == expected_full_name);
}
CheckFullName("Doug Adams", "Mr. Douglas Adams", "");
CheckFullName("Jake Brown", "Mr. Jake Brown III", "");
CheckFullName("No Such Guy", "", "no match found");
CheckFullName("John", "", "more than one result");
after
details = request.POST.get('details');
location = request.POST.get('location');
phone = request.POST.get('phone');
email = request.POST.get('email');
url = request.POST.get('url');
의미 있는 순서를 선택하고 일관성 있게 사용하라
|
- 변수의 순서를 HTML 폼에 있는 <input> 필드의 순서대로 나열하라.
- '가장 중요한 것'에서 시작해서 '가장 덜 중요한 것'까지 순서대로 나열하라.
- 알파벳 순서대로 나열하라.
before
class FrontendServer {
public:
FrontendServer();
void ViewProfile(HttpRequest* request);
void OpenDatabase(string location, string user);
void SaveProfile(HttpRequest* request);
string ExtractQueryParam(HttpRequest* request, string param);
void ReplyOK(HttpRequest* request, string html);
void closeDatabase(string location);
}
after
class FrontendServer {
public:
FrontendServer();
~FrontendServer();
// 핸들러들
void ViewProfile(HttpRequest* request);
void SaveProfile(HttpRequest* request);
// 질의/응답 유틸리티
string ExtractQueryParam(HttpRequest* request, string param);
void ReplyOK(HttpRequest* request, string html);
// 데이터베이스 헬퍼들
void OpenDatabase(string location, string user);
void closeDatabase(string location);
}
- 비슷한 생각을 하나로 묶어서, 성격이 다른 생각과 구분한다.
- 문단은 '시각점 디딤돌'역할을 수행한다. 문단이 없으면 하나의 페이지 안에서 읽던 부분을 놓치기 쉽다.
- 하나의 문단에서 다른 문단으로의 전진을 촉진시킨다.
after
def suggest_new_friends(user, email_password):
# 사용자 친구들의 이메일 주소를 읽는다.
friends = user.friends()
friend_emails = set(f.email for f in friends)
# 이 사용자의 이메일 계정으로부터 모든 이메일 주소를 읽어들인다.
contacts = import_contacts(user.email, email_password)
contact_emails = set(c.email for c in contacts)
# 아직 친구가 아닌 사용자들을 찾는다.
non_friend_emails = contact_emails - friend_emails
suggested_friends = User.objects.select(email_in=non_friend_emails)
...
return render("suggested_friends.html", display)
- 일관성 있는 스타일은 '올바른' 스타일보다 더 중요하다.