[우테코] 사다리 타기 피드백

이건회·2023년 2월 24일
0

우테코

목록 보기
9/19

개요


우아한테크코스 2단계 사다리 타기 미션에 대한 코치님의 피드백 내용을 정리해 보았다

어떠한 방식으로 접근할 것인가?


Out -> In, In -> Out 접근 방식

  • Out -> In 방식 : 큰 단위부터 접근한다. 요구사항을 보면서 큰 설계를 하고 세부 내용을 객체로 도출한다. 도메인 지식이 없거나 요구사항을 객체로 도출할 수 없는 경우 적합하다. 즉 처음부터 작은 단위를 뽑아낼 수 없을 때 사용한다.
  • In -> Out 방식 : 작은 단위부터 만들어가며 점차 설계를 확장해 나간다. 도메인 지식이 있거나, 요구사항을 객체로 도출할 힌트가 보일 때 사용할 수 있다. 즉 보자마자 작은 객체 단위로 뽑아낼 내용이 보일 때 사용할 수 있다.

그러나 현실적으로 어떤 방식을 선택할지에 대한 기준은 매우 애매하다

따라서 흔히 이러한 선택을 한다

Out 부터 In으로 접근해서 In Out으로 구현한다
-> 큰 부분에서 설계하다가 도메인에 대한 지식이 늘어나면 In Out으로 전환한다

Out->In, In->Out 방식은 핑퐁처럼 주고 받으며 사용할 수 있는 방법론이다.

추천 방법

  1. Out->in 으로 할 수 있는 곳 까지만 접근 + 설계를 한다
  • 요구사항을 분석한다
  • 도메인 설계에서 Object Graph중 가장 마지막 노드, 즉 의존성을 가지는 객체가 하나도 없는 객체부터 구현을 시작할 생각을 한다. 이래야 TDD로 접근하기 수월함

ex)

public class LadderGame {
	// 사다리를 어떻게 만들어야 할까
    // 라인 안의 포인트
    
    class Name{}
    
    class Line{}
    
    
}
public class Line {
	
    private final List<Boolean> line ;
    
    //생성자
}
public class LineTest {
	
    @Test
    void 생성테스트()
}
  • 테스트를 만들고 나니 Line을 어떻게 생성해야 할지 고민이다. 단순 Boolean으로 감싸기에는 각 사다리의 위치도 객체로 필요할 듯 싶다
public class Point {
	//코드
}
public class Line {
	
    private final List<point> line ;
    
    //생성자
}
  • 따라서 다음과 같이 조금 더 작은 단위를 찾을 수 있다 -> 이게 상위 개념으로 작은 단위를 찾는 Out -> In 방식이다.
  • 그러나 기존 코드에 대한 테스트는 다 깨질 것이다. 이 때 필히 삭제를 하고 다시 코드를 짜야 한다. 삭제를 하지 않고 코드를 짜다 보면 코드의 부채가 생긴다 -> 즉 실시간으로 레거시가 쌓이게 되는 것
    -> 그러나 Out -> in 방식은 설계가 이상해질 수 있다. Out->In으로 전부 구현하면서 도메인에 대한 지식이 늘어났다? 그렇다면 기존 코드를 삭제하고 In->Out 으로 다시 구현해도 괜찮다!
public class Point {
	publinc int movedirection(int position){
    	return position
        };
}
  • 아래나, 오른쪽으로 이동하는 경우를 생각하며 코드를 추가한다
class PointTest {
	
    @Test
    void 1인위치가_아래로_내려가면_위치가_1() {
    	final var point = new Point();
        //포인트가 아래로 내려갈 수 있다
        final var position = point.movedirection(1);
        assertThat(position).isEqualto(1);
    }
    
    @Test
    void 2인위치가_아래로_내려가면_위치가_2() {
    	final var point = new Point();
        //포인트가 아래로 내려갈 수 있다
        final var position = point.movedirection(2);
        assertThat(position).isEqualto(2);
    }
    
    
    //어떻게 오른쪽으로 point가 이동하게 할 수 있을까?
    @Test
    void 2인위치가_오른쪽으로_내려가면_위치가_3() {
    	final var point = new Point();
        //포인트가 아래로 내려갈 수 있다
        final var position = point.movedirection(2);
        assertThat(position).isEqualto(3);
    }
    
}
public class Point {

	private boolean right;
    
	publinc int movedirection(int position){
     if (position.right){
     	position++
        }
    };
}
  • 왼쪽으로 이동하는 경우도 생각해 본다
class PointTest {
    
    //어떻게 왼쪽쪽으로 point가 이동하게 할 수 있을까?
    @Test
    void 2인위치가_왼쪽으로_내려가면_위치가_1() {
    	final var point = new Point();
        //포인트가 아래로 내려갈 수 있다
        final var position = point.movedirection(2);
        assertThat(position).isEqualto(3);
    }
    
}
public class Point {

	private boolean right;
    
	publinc int movedirection(int position){
     if (position.right){
     	return position++
        }
     if (position.left){
     	return position--
        }
     
    };
}
  • 그러나 둘 다 true일 경우도 생기므로 예외를 처리한다
  • 또 위치가 0일 때, 위치가 맨 끝일때는 왼쪽, 오른쪽으로 갈 수 없어야 한다
public class Point {

	private boolean right;
  	private boolean left;
    
    public Point(boolean left, boolean right){
    	if (둘다 true){
        	new 예외();
        }
    }
    
	public int movedirection(int position){
     if (position -1 <0){
     	throw new 예외();
     }
     if (position.right){
     	return position++
        }
     if (position.left){
     	return position--
        }
     
    };
}
  • 다음과 같이 짜다보면 어느 순간 클래스의 역할이 많아진다
    -> 이 때 클래스의 분리를 생각해 볼 수 있을 것이다
public class Position {
	private final int value;
    
    Position(int value){
    	if (value -1 <0){
     		throw new 예외();
        this.value = value;
     }
    }
}
public class Point {

	private boolean right;
  	private boolean left;
    
    public Point(boolean left, boolean right){
    	if (둘다 true){
        	new 예외();
        }
        //주입
    }
    
	public Position movedirection(int position){
     if (right){
     	return new Position(position+1);
        }
     if (left){
     	return new Position(position-11);
        }
     
    };
}
  • Position이라는 클래스를 만들어 움직일 수 있는 위치 값을 관리한다
public enum Direction {
	LEFT,
    RIGHT,
    STRAIGHT
}
  • enum을 만들어 반복되는 left, right를 하나로 묶을 수 있다.
public class Point{

	private final Direction direction;
    
	public Point(Direction direction){
    	this.direction = direction
    	//
    }
    
    // ENUM 기반으로 기존 코드 리팩터링
}

중요한 것

-> 큰 개념에서 만들다가 필요성이 느껴지는 순간 하위 개념을 만들 수 있고, 역할도 위임할 수 있다.
-> 그러나 하위 개념을 만들 때 상위 개념을 고려하지 말자, 코드가 어려워지고 결합도까지 높아질 수 있다.
-> 현업에서는 Point를 만드는 개발자와 LadderGame을 만드는 개발자가 다를 수 있다. 따라서, 상위 개념에서 "LadderGame은 이래야 해!" 라고 하는 순간 결합도가 높아지는 것이다.

profile
하마드

0개의 댓글