본문 바로가기
JAVA

자바 플레이그라운드 with TDD, 클린코드(4)

by moonstal 2022. 6. 4.

4/21
문자열 계산기를 다시 만들었다.
값을 공유할 때 변수에 static붙이고 인스턴스 변수를 쓰지 않으면 메서드에 static 붙인다고 알고 있었다. 그래서 메서드에 static을 다 갖다 붙였다. 뭔가 잘못된 느낌이었다. static쓰니까 객체생성을 하나도 안했다. 나는 인스턴스 변수를 쓰지 않고 있었고 값들은 매개변수로 계속 넘기고 있었다. 이건 객체지향적인 코드가 아니었다.

 

객체지향 프로그래밍으로 유틸리티 클래스를 대체하자. | Mimul Tech log

유틸리티 클래스를 안써본 사람은 거의 없을겁니다. 유틸리티 클래스가 좋다, 나쁘다는 논쟁꺼리지만, 객체지향의 관점에서 볼때 그래도 생각해볼 꺼리가 된다고 생각해, OOP Alternative to Utility Cl

www.mimul.com

절차적 메소드 호출

int max = NumberUtils.max(10, 5);

객체지향적인 방법

int max = new Max(10, 5).intValue();


또 계속 public으로만 쓰고있었다. 왜 private을 쓰는지 이론적으로만 알고 있었는데 이제야 깨달았다. 다른 곳에서 호출할 때 이 메서드 하나면 되는데 숨겨져 있어야 할 메서드들과 변수들이 튀어나왔다.

테스트코드도 완전 잘못한 느낌, 메서드 조금 수정하면 테스트 코드도 계속 바꾸게 되고 뭔가 이상했다. 조금 수정해서 될게 아니었다. 그래서 다시 싹 다 갈아엎었다.

다시 만들면서 Number 객체를 만들어봤다. 전에는 입력받는 곳에서 값을 체크했는데 Number 클래스 만들어놓으니까 여기서 관련된 메서드를 만들 수 있었다. 좀 발전한 느낌이 든다. 이번에는 private가 많아졌다. 마지막에 코드를 수정 했는데 테스트 코드를 돌려봤을 때 똑같이 잘 작동했다.신기하다. 안에 내용을 바꿔도 테스트가 통과한다는게 이 말인가? 아직 모르겠는건 객체가 어떻게 협력한다는 건지, 무슨 책임을 부여해야하는 건지,, 일단 또 마음대로 하는 중이다.. 할 수 있겠다 싶은 것들 위주로 해봐야겠다.

4/25
오브젝트 1장을 봤다. 궁금했던 내용들이 들어있었다.
뭐를 열고 닫아야 할지, 역할과 책임 그리고 협력이 무엇인지를 어렴풋이나마 알 것 같다. 책에 있는 코드를 읽는데 이야기가 쓰여진 것처럼 코드가 작성되어있었다. 신기한 경험이었다.
객체지향 사실과 오해가 더 얇고 좀 더 쉬워보여서 그냥 이것부터 읽을까했는데 앞부분을 읽으면서 계속 궁금한게 그래서 그런 코드가 뭐지?라는 생각이 들었다. 왜 오브젝트를 먼저 읽을 것을 추천하는지 알 것 같았다.

4/26
자동차 경주게임을 만들었다. 포장하라는 말을 완벽히 이해하진 못했지만 만들어보고 싶었다. 또 오브젝트 책을 보고 나는 객체가 협력하는게 아니라 그냥 메인에 다 생성해서 부르고 있었던 것 같아서 이번엔 협력시키고 싶었다. 또 Car는 Name을 갖고 있고, Cars는 Car를 갖고 있고, Racing을 하는 곳에는 Cars가 있었으면 했다. 잘 되어가나 싶었는데 뒤로 갈수록 메서드가 안에 숨겨져 있어서 꺼내고 싶은데 어떻게 불러야하지.. 뭐를 리턴해야하나..고민하다가 머리속이 뒤죽박죽 되었고 여기저기서 결과를 찍어냈다. 마지막엔 냅다 구현이 되어버렸다.

4/28
좌표계산기
이번엔 먼저 메인에다가 짰다. 객체를 만들지 않고 그냥 하니까 확실히 더 쉬웠다. 처음부터 객체를 설계하고 완벽하게 만들려고 하기보다는 일단 구현해보는 것도 좋은 것 같다.  MVC를 어떻게 구현해야하는지 피드백 자료를 보고 이제야 어떤 느낌인지 알 것 같다. 자동차 경주에서 어떻게 해야할지 몰라서 막 찍어냈는데 이 방식으로 좌표계산기 다시 만들어보고 자동차 경주에도 적용해봐야겠다.

 

5/6

피드백 자료를 보고 좌표계산기를 다시 만들어 봤다. 메인에다 짤 때는 게임 진행 순서대로 쉽게 구현이 되었는데 객체와 메서드를 만들려고 하니까 처음 인풋에서부터 막혔다. 리턴이 선, 사각형, 삼각형으로 나오도록 해야하는데 리턴을 하려면 일단 리턴할 객체부터 만들어야했다. 커밋의 단위도 자꾸 뒤죽박죽 되고 이거 만들었다가 저거만들었다가 하게되었다. 또 고민이 되었던 건 문제 진행순서는 선을 만든 뒤에 사각형, 삼각형을 만들도록 되어있는데 처음부터 추상클래스를 만들어 상속을 적용할지 진행하면서 고쳐나갈지 고민하다가 추상클래스를 만들었는데 너무 편했다. 

public class CoordinateController {
    public static void run(){
        Figure figure = InputView.input();
        ResultView.report(figure);
    }
}

사용자 입력에 따른 선, 사각형, 삼각형을 Figure 하나로 표현할 수 있었다. 다형성 정말 좋다.

 

5/13

좌표계산기를 하고나니까 자동차 경주게임에서 결과를 여기저기 찍어냈던 것을 고쳐볼 수 있을 것 같았다. 또 MVC방식을 적용해 보고 싶었다.

 

처음 코드

public class Main {
    public static void main(String[] args) {
        InputView inputView = new InputView();
        Racing racing = new Racing();

        List<Car> cars = inputView.gameStart();
        int tryNumber = inputView.enterTryNumber();

        for(int i=0;i<tryNumber;i++){
            for(Car car:cars){
                racing.isMoveable(car,racing.makeRandomNumber());
                System.out.print(car.getName()+":");
                racing.printPosition(car);
            }
            System.out.println();
        }

        Result result= new Result();
        result.pickWinners(cars);
        result.printWinners();

    }
}

다시 짠 코드

public class RacingController {
    public void run() {
        List<Car> cars = InputView.inputCarsName();
        int times = InputView.inputTimes();

        Racing racing=new Racing(cars);
        racing.playGame(times);

        ResultView.showHistory(racing);
        ResultView.showWinner(racing);
    }
}

처음 짰던 코드랑 비교했을 때 메인에 덩그러니 있던 이중반복문을 Racing안으로 넣고 메서드를 만들어 분리했다. 결과는 ResultView에서만 찍도록 했다. 원시값을 포장하라는 것도 Name과 Position을 만들어 적용해봤다. 만들면서 적용하는게 많아질수록 발전하고 있다는 느낌이다. 문제는 제대로 알고 사용하고 있는가이다. 내 멋대로 이해하고 나중에 보면 아닌 경우가 있다. 일단 mvc 부터 제대로 이해해야 할 것 같다.

 

6/2

블랙잭

조건이 많아보여 손이 가질 않았는데 동욱님과의 두번째 멘토링을 하고 빨리 만들어 봐야겠다는 생각이 들었다. 멘토링 때 주신 action item들을 하나씩 클리어하고 싶었기 때문이다. 일단 베팅기능을 빼고 플레이어는 한명으로 해서 난이도를 낮췄다. 만들면서 의문이었던 건 player.getCards().sumScore() 이런식으로 줄줄이 사탕처럼 이어지는데 이게 맞나싶고 어려웠던 건 메서드 이름정하기..이번에 발전한건 필요에 의해 스트림을 사용해본 것. 플레이어가 보유한 카드들을  " , "로 조인하는게 목적이었는데 for문 돌려서 하려니 그게 더 복잡할 것 같았다.

public String retain() {
        return cards.stream().map(card -> card.retain()).collect(joining(", "));
    }

만들기 전엔 엄두가 안나서 동욱님이 쓰신 객체지향 좀 더 이해하기-블랙잭 게임 구현도 여러번 읽었다. 막상 시작하니까 시간가는 줄 모르고 만들었다.

 

이 과정을 하면서 테스트코드 작성하는 방법과 클린코드가 무엇인지도 배웠지만 가장 좋았던건 스스로 만들어보는 경험을 했다는 것이다. 만들어보면서 나는 그동안 공부를 제대로 한적도, 제대로 알고있는 것도 없었다는 것을 깨달았다. 이제라도 알게되어서 정말 다행이다. 필요한 만큼 공부하고 만들어보는 것도 너무 좋았다. 이제 프로그래밍이 뭔지 조금 알 것 같고 단순히 강의를 따라치다보면 안다고 착각할 때가 있는데 이 기능을 구현하기 위해서 어떤 메서드를 만들어야 할지 생각하면서 발전을 할 수 있었던 것 같다. 클린코드와 테스트코드 작성, 객체지향설계는 꾸준히 연습해야할 것 같다.