티스토리 뷰

더 좋은 프로그래밍 하기

  • setter 지양

Setter은 왜 지양해야 할까? set이라는 것은 초기화의 의미를 담고 있다. 객체가 만들어질 때, 초기화하는 역할은 생성자이다. 생성자의 역할은 적절한 유효성 검사를 통한 초기화이다. 따라서 초기화는 생성자로 하는 것이 좋다. 초기화 이후에도 내부 값을 변경하게 될 수도 있는데 이때는 set이라는 키워드를 사용하여 메서드 이름을 설정하기보다는 적절한 이름을 지어주는 것이 좋다. 하는 역할이 같더라도 객체가 외부의 값을 받아 능동적으로 변경하는지, 외부의 호출에 의해 수동적인 값 변경이 되는지 느낌의 차이라고 생각한다.

 

  • getter 지양

setter/getter를 지양하라는 것은 핵심 비즈니스 로직을 구현하는 도메인 객체에 해당한다. Domain 객체와 DTO 객체는 차이가 있다. Domain Model은 비즈니스 로직만을 가지고 있는 핵심 객체이다. DTO(Data Transfer Object)는 객체 간에 데이터를 전달해주는 객체이다. 따라서 View에서 나타내기 위해 getter를 사용하는 경우가 많다. DTO의 역할도 같이 하고 있는 경우에는 getter를 허용한다.

 

  • 객체를 객체처럼 사용하기

객체는 객체처럼 사용해야 한다. 객체는 데이터를 담아두는 곳이 아니다. 행동(역할과 책임)이 주어지고, 그에 맞는 데이터를 가지고 있는 것이다. 객체를 좀 더 하는 일에 집중해서 만들자.

Tips

less Methods, more Constructors

적은 메서드로 단일 책임 원칙을 지키고, 더 많은 생성자로 객체 사용의 활용도를 높일 수 있다.

5개 이하의 메서드를 가지고, 5개 이상의 생성자를 가지는 클래스가 좀 더 좋은 클래스에 가깝다.

 

가장 좋은 패키지는 10개 이상의 클래스를 가지지 않는다.

객체의 책임을 분배하여 단일 책임 원칙을 지키려고 하는 것처럼 패키지도 세분화되어 적절한 책임 분배가 이루어져야 한다.

생성자 체이닝 : this()

주생성자와 부생성자를 두고 this()로 생성자 체이닝(생성자 역할 위임)이 가능하다. this는 인스턴스화 된 자신을 가리킨다. 따라서 this()를 사용한다는 것은 인스턴스 자신의 인스턴스화(생성자 호출)를 한다는 것을 의미한다. 검색을 해보니 주생성자, 부생성자의 개념은 코틀린에서 많이 사용되는 듯하다. 하지만 super()를 사용해서 상위 클래스의 생성자를 호출하는 것처럼 this()를 통해서 생성자 체이닝으로 자신의 또 다른 생성자에게 역할을 위임할 수 있다.

public Car(String carNameValue) { // 부생성자
        this(carNameValue, Position.getZeroPosition());
}

public Car(String carNameValue, Position position) { // 주생성자
        this.carName = new CarName(carNameValue);
        this.position = position;
}

원시 값 포장

원시 값을 왜 포장해야 할까? 여기서 의미하는 원시 값은 매개변수로 사용하는 의미있는 값을 의미한다. 예를 들어보자. int positionint number는 다르다. position은 단순한 숫자가 아니라 위치라는 값을 숫자로 표현하는 것이다. 위치는 나의 설정에 따라 음수일 수 없다. 따라서 position은 Position 으로 포장되면 좋다. Position 이라는 위치 값을 가진 객체가 있다면 이것은 음수가 아님을 보장할 수 있다. 의미있는 값을 포장하여 설정에 따른 값을 가지게 책임을 부여함으로써 책임있는(보장되는) 의미있는 값이 되는 것이다. 해당 값의 의미를 더 신뢰하고 사용이 가능하다. 이렇게 되면 validate 체크도 Position의 생성자에서 해주게 되며 역할과 책임이 명확해진다.

일급 컬렉션

내부에서만 컬렉션 조작이 가능하도록 컬렉션(List 등)을 포장한다. 일급 컬렉션은 반드시 컬렉션을 제외한 다른 멤버 변수가 없어야 한다.(이때 상수는 제외되는 듯 하다) 커스텀된 컬렉션이 되는 것이다.

일급 컬렉션은 적절한 이름을 가지며, 나의 의도대로만 컬렉션 조작이 보장된다. 상태와 로직이 한 군데에서 관리된다.

 

[예시]

Cars라는 이름을 가진 커스텀 컬렉션이 만들어졌다. Cars는 초기화 될때만 추가 가능하다. Cars안에 있는 Car를 움직이는 것은 raceOneLap이라는 Cars의 메소드에 의해서만 가능하다. getCars로 리스트를 받아올 수 있지만, 불변으로 만들었기 때문에 수정이 불가능해진다. 내가 의도한 대로만 리스트 조작이 가능하게 된 것이다. Car이라는 상태들을 가지며 그것을 조작하는 로직도 Cars에서만 관리된다.

// 내가 생각했을 땐, 일급 컬렉션 
// (하지만, 아직 일급 컬렉션에 대해 잘 모르기 때문에 사실이 아닐 수 있다.) 
public class Cars { 
    private static final int MINIMUM\_CAR\_AMOUNT = 2; 
    private static final int START = 0; 
    private static final int END = 9; 

    private final List<Car> cars = new ArrayList<>(); 

    public Cars(List<String> splitCarNames) { 
        validateNumberOfCar(splitCarNames); 
        validateSameName(splitCarNames); 
        splitCarNames.forEach(carName -> cars.add(new Car(carName))); 
    } 

    public void raceOneLap() { 
        cars.forEach(car -> car.move(RandomUtil.nextInt(START, END))); 
    } 

    public List<Car> getCars() { 
        return Collections.unmodifiableList(cars); 
    } 
}

정리

설 연휴를 제외하면 일주일?! 정도 배우고 학습했지만, 많은 것을 학습할 수 있었다. 프로그래밍을 하는데 도움이 되는 좋은 방식들을 많이 접할 수 있었다. 미션1을 하면서 아직 내가 큰 항목으로 정리하기엔 아직 애매하지만, 수업시간에 배웠던 유용한 내용들을 종합하여 정리하였다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함