[책 소개]  애자일 소프트웨어의 혁명적인 패러다임을 제시하는 책이다. 저자 로버트 마틴은 오브젝트 멘토(Object Mentor)의 동료들과 힘을 모아 ‘개발하며’ 클린 코드를 만드는 최상의 애자일 기법을 정제하여『Clean Code 클린 코...

[안드로이드] Clean Code 리뷰 (정적 팩토리 메서드, try-catch문)



[책 소개]
 애자일 소프트웨어의 혁명적인 패러다임을 제시하는 책이다. 저자 로버트 마틴은 오브젝트 멘토(Object Mentor)의 동료들과 힘을 모아 ‘개발하며’ 클린 코드를 만드는 최상의 애자일 기법을 정제하여『Clean Code 클린 코드』에 담았다. 아주 많은 코드를 읽고 그 코드의 무엇이 옳은지, 그른지 생각하며 전문가로서 자신이 지니는 가치를 돌아보기 위해 꾸준히 노력한다면, 이 책을 통해 여러분의 프로그래밍 실력은 한층 더 높아질 것이다.

 최근 '클린코드' 라는 책을 읽었는데, 몇가지 기록하고 싶은 내용있어 아래 정리합니다.
 
 
 

클린코드(Clean Code) 주요내용

 ♣ 제대로 짤 시간이 없다고 생각해서... 나중에 정리하겠다고 다짐한다... 그러나 나중은 결코 오지않는다.

  깨끗한 코드란? 코드를 봤을 때 다른사람이 이해하고 고치기 쉬운 코드 (Big Dave Thomas)

 ♣ 클래스 이름은 명사나 명사구가 적합하다. Manager, Processor, Data, Info 등과 같은 단어는 피하고, 동사는 사용하지 않는다. ex) Customer, Account

 ♣ 메서드 이름은 동사나 동사구가 적합하고, 생성자를 구현 할 때 정적 팩토리 메서드를 사용한다.

 ♣ 함수는 한 가지를 해야하고 그 한가지를 잘해야 한다. 함수는 작게 만들어라.

 ♣ 함수 이름은 짧고 어려운 것보다 길고 서술적인 이름이 좋다.

 ♣ 함수 인수 갯수는 많을수록 함수의 개념을 이해하기 어렵게 만든다.

 ♣ 오류코드보다는 예외처리(try/catch)를 사용한다. 그리고 정상 동작과 오류 처리 동작을 함수로 뽑아서 구분짓는게 코드 이해하기 쉽다.

 ♣ null 을 전달하지마라. null 을 반환하지마라. 일거리만 늘릴뿐이다.



주요내용 중에서 정적 팩토리 메서드 및 예외처리에 대해서 간단하게 정리하고 마무리하려고합니다:) 
 


정적 팩토리 메서드

장점
 - 가독성이 좋다.

class Character {
    private int strength, intelligence;

    public Character(int strength, int intelligence) {
        this.strength = strength;
        this.intelligence = intelligence;
    }

    // 정적 팩토리 메소드
    public static Character newWarrior() {
        return new Character(10, 5);
    }

    // 정적 팩토리 메소드
    public static Character newWizard() {
        return new Character(5, 10);
    }
}

 생성자를 사용했을 때
Character warrior = new Character(10, 5);
Character Wizard = new Character(5, 10);

 정적 팩토리 메서드를 사용했을 때 naming 이 가능 하기 때문에 가독성이 올라간다.
Character warrior = Character.newWarrior();
Character wizard = Character.newWizard();

 - 호출할 때마다 새로운 객체를 생성할 필요가 없다.

class Character {
    private int strength, intelligence;
    private static final Character character = new Character();

    private Character() {
    }

    // 정적 팩토리 메소드
    public static Character newWarrior(int strength, int intelligence) {
        setStrength(strength);
        setIntelligence(intelligence);
        return character;
    }

    // 정적 팩토리 메소드
    public static Character newWizard(int strength, int intelligence) {
        setStrength(strength);
        setIntelligence(intelligence);
        return character;
    }

    public void setStrength(int strength) {
        this.strength = strength;
    }

    public int getStrength() {
        return this.strength;
    }

    public void setIntelligence(int intelligence) {
        this.intelligence = intelligence;
    }

    public int getIntelligence() {
        return this.intelligence;
    }
}
 정적 팩토리 메서드를 호출할 때마다 객체를 생성하지 않고, 하나만 만들어 놓은 상태로 사용자의 요청이 있을때마다 미리 만들어진 객체를 반환해주어 사용할 수 있다.

 - 하위 자료형 객체를 반환할 수 있다.

abstract class Character {
    private String name;

    private Character(String name) {
    }

    // 정적 팩토리 메소드
    public static Character newCharacter(String name) {
        if (name.equals("warrior")) {
            return new Warrior(10, 5)
        } else if (name.equals("wizard")) {
            return new Wizard(5, 10)
        }
    }
}

class Warrior extends Character {
    private int strength, intelligence;

    private Warrior(int strength, int intelligence) {
        this.strength = strength;
        this.intelligence = intelligence;
    }
}

class Wizard extends Character {
    private int strength, intelligence;

    private Wizard(int strength, int intelligence) {
        this.strength = strength;
        this.intelligence = intelligence;
    }
}
 생성자는 자기 자신만을 반환할 수 있다. 그와 다르게 위 코드에서 정적 팩토리 메서드는 호출함에 따라 Character Class 의 하위 객체인 Warrior, Wizard 를 반환 할 수 있는 유연성을 가지고 있다.

단점
 - 정적 팩토리 메서드만 있는 클래스라면, 생성자가 없으므로 하위 클래스를 못 만든다.
 - 정적 팩토리 메서드는 다른 정적 메서드와 구분이 어려울 수 있다.
 
 


오류코드보다는 예외처리(try/catch)

오류코드 사용
if (deletePage(page) == E_OK) {
    if (registry.deleteReference(page.name) == E_OK) {
        if (configKeys.deleteKey(page.name.makeKey())) == E_OK) {
            logger.log("page deleted");
        } else {
            logger.log("configKey not deleted");
        }
    } else {
        logger.log("deleteReference from registry failed");
    }
} else {
    logger.log("delete failed")
    return E_ERROR;
}

try-catch 문 사용
try {
    deletePage(page);
    registry.deleteReference(page.name);
    configKeys.deleteKey(page.name.makeKey());
} catch {
    logger.log(e.getMessage());
}
오류코드를 사용하면서 여러 단계를 거쳐야되는 경우 위와 같이 if 문이 중첩되는 경우가 발생 할 수 있다. 반면 try-catch 문으로 동작 및 오류처리가 분리되어 깔끔해지는 경우가 있다. (무조건 try-catch 문을 사용하라는건 아니겠지만 고려해야하는 부분은 맞는것 같습니다.)



끝으로..

 책을 전부 다 읽은 것은 아니지만... 확실한건 코딩하는데 있어서 단순히 빌드를 성공시키고 결과물에만 집중했던건 아닌가라는 생각을 하게 됐습니다. 이제서야 이 책을 읽은 것이 좀 아쉽습니다. 코딩에 관심있는 분이라면 꼭 추천 드리고 싶습니다.

0 comments: