[Clean Code] 3장 함수 (2)
서술적인 이름을 사용해라
함수는 어떤 동작을 하는 것이다. 따라서 함수의 이름은 동작을 서술해야 한다. 그것이 함수의 "좋은 이름"인 것이다. 좋은 이름의 가치는 2장에서 많이 얘기했다.
함수의 이름이 길어져도 상관없다. 이름을 직접 넣어보고 읽어본 후 결정해도 된다. 어차피 우리는 IDE를 사용하고 IDE는 자동완성을 지원하니까! 한 모듈(클래스) 내에선 이름에 사용된 단어들이 일관성 있어야 한다. 회원을 만드는 함수를 createMember() 라 했으면 게시글을 만드는 함수는 createPost() 여야 하지 makePost()이면 안되고, 회원탈퇴는 deleteMember()이여야 하지 deleteUser()이면 안된다.
함수 인수
public void function(){
}
public void function(Object obj){
}
public void function(Object obj1, Object obj2 ...){
}
기본적으로 함수의 인수는 적을수록 좋다. 함수의 인수가 많아지면 이를 해석할 수 있는 경우의 수가 많아진다. 예를들어 인수로 넘어온 두 객체를 비교하는 compare 함수가 있다고 하자.
public int compare(Data standard, Data target){
return standard.value - target.vlaue;
}
이 경우, 인수의 순서에 따라 결과가 정 반대로 된다. 근데, 인수로 넘어올 두 값에 자연적인 순서가 있는가? 아니 없다. 즉, 인위적으로 두 인수의 순서를 기억해야만 한다. 이 경우, 함수를 객체의 매서드로 만들면 인수를 한개로 만들어 헷갈리지 않게 할 수 있다.
public class Data{
int value;
public int compare(Data target){
return this.value - target.value;
}
}
다시한번 말하지만, 함수의 인자는 적을수록 좋다.
삼항 함수보단 이항 함수가, 이항함수보단 단항 함수가, 단항 함수보단 무항 함수가 더 좋다. 각 종류의 함수가 필요할 경우가 있다.
- 단항 함수 : 인수에게 질문을 던지는 경우 , 안수를 다른것으로 변환하여 반환하는 경우
fileManager.existFile("test"); int number = Integer.parseInt("120");
- 이항 함수 : 자연적으로 인수사이에 순서가 있고, 자연적으로 두가지 값의 묶음으로 표현되는 경우
Point point = new Point(0,0); // 직교좌표계에서의 한 점을 표현하는 객체. 당연히 인수는 x좌표, y좌표이다
- 삼항 함수 : 수정할 수 없는 상위 라이브러리에서 삼항함수를 사용하여 어쩔 수 없는 경우.
만약, 함수의 인수로 2-3개 이상을 전달해야 할 경우 인수를 묶어서 하나의 객체로 만드는 것을 고려해야 한다.
public void makeMember(String id, String name, String pw, String address){
}
public class Member{
String id;
String name;
String pw;
String address;
}
public void makeMember(Member member){
}
훨씬 더 자연스럽게 읽히는 함수가 만들어진다.
출력인수를 사용하는 건 아주아주 나쁘다. 출력인수란, 함수의 결과로 함수의 인수가 변경되는 것을 말한다.
public void appendFooter(Report report){
}
Report.appendFooter(); // 이런 구조가 더 합리적이다.
만약 어떤 객체의 상태가 변경되어야 한다면, 객체를 인자로 넘길 것이 아니라, 객체의 함수를 호출하여 상태를 변경해야 마땅하다.
함수는 객체의 상태를 변경하거나, 객체의 상태를 반환해야 한다. 둘 다 하면 안된다.
public Member setId(String id){
this.id = id;
return this;
}
public void setId(String id){
this.id = id;
}
출력인수는 객체지향프로그래밍이 등장하기 전에 사용하던 것이다. 객체지향에선 더이상 필요하지 않다.
함수의 이름과 인수의 이름은 동사/명사 쌍으로 이루어져야 한다.
함수는 부수효과(side-effect)를 일으키면 안된다. 아래 코드에서 부수효과를 찾아보자.
public boolean checkPassword(String userName, String password){
Member member = memberService.getMember(userName);
if(password.equals(member.getPassword()){
Session.init();
return true;
}else{
return flase;
}
}
부수효과는 Session.init() 이다.
이 함수는 비밀번호를 확인하는 함수다. 함수 이름 어디에도 세션을 초기화하는 말은 없다. 만일, 프로그래머가 이 함수를 호출하여 비밀번호를 확인하려 했는데, 갑자기 세션이 초기화되면 프로그래머가 당황할 것이다.
명심하자. 함수가 하는 일은 모두 함수의 이름에 드러나야한다.
오류코드보단 예외를 사용하자
함수가 오류코드를 반환하면 이 함수를 호출한 쪽에선 즉시 오류를 처리해야 한다. 즉, 정상처리와 오류처리 코드가 뒤섞이게 된다.
if(deleteMember("test") == ERROR){
...
}else{
if(deletePost(member) == ERROR){
...
}else{
...
}
}
try{
deleteMember("test");
deletePost(member);
}catch(Exception e){
logger.log(e);
}
예외를 사용하면 훨씬 깔끔해진다.
반복하지 말아라
모든 문제의 근원은 반복이다. 반복은 아주 나쁘다.