ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [우아한테크코스] 3주간의 프리코스 후기
    휴먼띵킹 2020. 12. 15. 07:40

    지난 10월부터 모집한 '우아한테크코스'(이하 우테코)에 지원하여 운이 좋게도 1차 합격하였고, 3주간 프리코스에 참여하였습니다. 길지 않은 시간이었지만, 시간으로 평가할 수 없을 만큼 많은 것을 깨달았고 공부한 뜻깊은 시간이었기 때문에 평생 기억하고 싶어 짧게나마 하나의 글로 후기를 남기기로 하였습니다. 자기소개서 제출과 코딩 테스트 과정이 있었지만 따로 작성하기로 하고 이 글에서는 후기에만 집중하겠습니다

    우테코란?

    저의 체중 증량을 이끌었던

    배달의민족 개발사 우아한형제들이 지원하는 프로그래밍 교육과정으로서, 서비스를 개발하는 회사에 재교육 없이 현장의 업무를 수행하도록 하는 것이 교육 목표라고 합니다.

     

    프리코스 진행 방식

    우선 간단하게 프리코스에 대해 설명하자면, 매주 수요일마다 이메일을 통해 미션이 주어졌고 완성되면 깃허브에 Pull Request 하는 방식으로 진행되었습니다. 미션은 JAVA로 수행해야 하고 모두 콘솔로 진행되는 프로그램을 만드는 일입니다. 어떤 기능을 구현해야 할지 기능 사항이 주어지고, 입출력을 어떻게 해야 하는지 명확한 요구사항이 주어지기 때문에 콘솔 게임쯤이야... 얼핏 보기엔 쉬워 보였습니다. 하지만 코딩 전에 기능 요구사항을 정리해야 하고, 여러 가지 프로그래밍 요구사항 등이 주어지기 때문에 막상 시작해보니 간단하게 느껴지지 않았습니다.

    프로그래밍 요구사항은 다음과 같은 것이 있습니다.

    • 자바 코드 컨벤션을 따른다.
    • indent는 depth는 3을 넘지 않도록 한다.
    • else 예약어, switch-case 문을 사용하지 않는다.
    • 함수의 길이가 15라인을 넘어가지 않도록 한다.
    • 3항 연산자를 사용하지 않는다.

    해당 주차 미션이 종료되면, 다음 미션과 함께 이전 미션에 대한 피드백을 보내주십니다.

    프리코스 참가자가 워낙 많기 때문에 개인별을 주시진 못하고 중요한 피드백을 모아 공통으로 보내주십니다. 다른 참가자분들에 대한 피드백도 담겨있는 것이기 때문에, 모르는 채로 지키고 있던 피드백 내용을 명확하게 정리할 수 있어서 좋았습니다.


    이렇게 앞선 요구사항과 피드백을 반영하다 보면 이 프리코스가 요구하는 게 읽기 좋은 코드라는 것을 자연스레 알게 됩니다.

     

    무엇을 느끼고, 배웠나?

    결론부터 이야기하자면 프로그래밍적으로는 객체지향을 배웠고, 정신적으로는 나는 개발을 좋아한다를 깨달았습니다.

    객체지향

    이 글을 작성하기 전에, 제 상태가 어땠는지 현재와의 비교를 위해  먼저 설명드리고 시작하겠습니다.

    저는 전공자이지만 편입생이고, 1년을 방황하다가 뒤늦게 군대를 다녀와서 4학년에 개발자가 되기로 마음먹은... 4년제 대학에서 사실상 1년 정도 배운 전공생이었습니다. (그 1년도 코로나로 인해 학교가 아닌 집에서 보냈습니다..)

    자바라곤 조건문, 반복문 정도만 알아서 1도 모르는 건 아니고 1 정도 아는 수준이었습니다. 그래서 프리코스 직전에 부랴부랴 이것이 자바다 라는 책을 구매해서 기본 문법과 이론을 공부하면서 진행했습니다.

     

    첫째 주에 제가 집중했던 부분은 indent depth가 2를 초과하지 않기메소드가 한 가지 일만 하도록 작게 만들기였습니다.

    메소드를 분리해 나가는데 '이거까지 분리해도 되나?' '얼마나 작게 해야 하지?'라는 고민을 내내 했던 것 같습니다.

    코드를 짜는 내내 '이게 맞나..'라는 생각을 했지만 한 가지 일만 하도록 작게 라는 말을 계속 떠올리며 진행했습니다.

    다음은 제가 첫째 주에 짰던 코드의 일부분입니다.

    public class Game {
      public void start() {
    
            boolean gameStart = true;
            while (gameStart) {
                int[] answer = RandomGenerator.generateRandomNumbers(BASEBALL_NUMBERS_LENGTH);
    
                boolean isCorrect = false;
                while(!isCorrect) {
                    int[] inputNumbers = takeInGameInput();
    
                    int strikes = countStrike(answer, inputNumbers);
                    int balls = countBalls(answer, inputNumbers);
    
                    printHint(strikes, balls);
                    isCorrect = checkResultBy(strikes);
                }
                gameStart = restartGame();
            }
        }
    }

    만약 요구사항이 없고, 메소드가 한 가지 일만 하도록 작게 만들기라는 키워드가 머리에 없었을 경우 어떻게 코드를 작성했을까? 를 생각해보니, 기능별로 메소드를 나누고 명확하게 변수명과 메소드명을 작성한 것에 뿌듯한 마음이 들었습니다.

    좋은 변수/메소드명을 고민함과 동시에 메소드가 한 가지 일만 하도록 하자 를 훈련한 1주 차였습니다.

    저는 이 코드를 제출하고 나서 '아주 보기 좋은 코드군'이라고 생각했습니다. 하지만 다른 참가자 분들의 코드와 두 번째 미션 메일을 봤을 때 정말 큰 깨달음을 얻었습니다.

    나는 객체지향 언어로 절차 지향적인 코드를 짰구나!

     

    사실 객체지향이 뭔지도 잘 몰랐지만, 저의 코드만 한 가지 클래스에서 놀고 있는 건 알 수 있었고, 두 번째 미션 메일에 클래스 분리에 도전해보라 라는 메세지를 보고 객체 지향과 관련이 있다는 것을 깨달아서 객체지향의 사실과 오해라는 책을 읽으며 객체지향을 공부하기 시작했습니다.

    첫 번째 미션의 피드백 중 기억에 남는 것은 반복하지 마라. 중복은 소프트웨어에서 모든 악의 근원이다. ,
    두 번째 미션의 피드백 중 기억에 남는 것은 java api와 collection을 적극 활용해라, 객체에 메세지를 보내라, 비즈니스 로직과 UI 로직을 분리하라 가 있었습니다.

    그리하여 이 모든 피드백을 적극적으로 반영할 세 번째 미션을 진행했습니다.

    세번째 미션은 지하철 노선도 프로그램인데, 첫 화면에서 기능에 따라 1, 2, 3, Q를 입력받고 그다음 화면에서 또다시 1, 2, ... , B를 입력받아야 했습니다.
    이때 생각할 수 있는 것은 else문을 쓸 수 없으니

    if (입력=="1") { 다음 화면 출력 } 
    if (입력=="2") { 다음 화면 출력 }  ...
    

    이 정도였는데, 썩 마음에 들지가 않았습니다.

    그러던 중, jojoldu 님의 블로그 게시물 중 Enum 활용 사례를 Enum에 대해 알게 되었고 아이디어를 얻었습니다.

    public enum MainMenu {
        MANAGE_STATION("1", "역 관리") {
            public void moveView(Scanner scanner) {
                StationMenu.openScreen(scanner);
            }
        }, 
       // ....
       // 입력으로 "1"이 들어왔을 때, MANAGGE_STATION 인스턴스를 리턴한다.
       public static MainMenu findOne(String input){
            return Arrays.stream(StationMenu.values())
                    .filter(x -> x.selection.equals(input))
                    .findFirst()
       }
    }
    

    다음과 같은 방식으로 enum을 작성했습니다. 하지만 여기서 가장 큰 문제가 발생했습니다.

    findOne 메소드는 MainMenu 타입만을 리턴할 수 있고, 4가지 화면을 구현해야 하니 4개의 클래스에 똑같은 메소드를 리턴 타입만 바꿔서 구현해야 했습니다. 이라고 불리는 중복이 발생한 것입니다.
    (실제로 코드를 조금만 수정해도 4개의 클래스에서 수정해줘야 하니 왜 악이라고 하는지 느꼈습니다.)


    static interface를 사용해서 제네릭 타입 매개변수로 Enum을 받고 공통되는 기능을 구현하려니, 매개변수로 받은 Enum은 제가 정의한 MainMenu의 속성을 가지고 있지 않았습니다.

     

    이 문제로 며칠밤을 고민하다가, 이 역시 jojoldu 님의 블로그 게시물을 통해 힌트를 얻어 생각보다 간단하게 해결하였습니다.

    // ENUM이 가지는 기능을 추상화하고 있다.
    public interface MenuModel {
        public String getSelection();
    
        public String getFeature();
    
        public void moveView(Scanner scanner);
    }
    
    // ENUM, 메뉴 선택에 대한 기능이 정의되어 있다.
    public enum MainMenu implements MenuModel {
        MANAGE_STATION("1", "역 관리") {
            public void moveView(Scanner scanner) {
                StationMenu.openScreen(scanner);
            }
        },
        ....
    }
    
    // 모든 메뉴들에서 사용하는 동일한 기능을 정의하고 있다.
    public class MenuFeature {
        public static MenuModel mapInputToSelection(Class<? extends MenuModel> menuType, String menuInput) {
            return Arrays.stream(menuType.getEnumConstants())
                    .filter(menu -> menu.getSelection().equals(menuInput))
                    .findFirst()
                    .orElseThrow(() -> new IllegalArgumentException(ErrorView.NOT_SELECTABLE_FEATURE));
        }
    }

    MenuFeature에서 Enum을 매개변수로 받았을 땐 정의한 MainMenu 로서 사용이 불가능했는데,
    MenuModel 인터페이스를 생성하고 MainMenu에서 구현하고, MenuFeature에서 (Class<? extends MenuModel> menuType ...) 로 매개변수를 받으니 정상적으로 MainMenu 로서 사용이 가능해졌습니다!!

     

    그 외에도 여러 가지 어려움이 있었지만 극복해나가다 보니 collection, stream, generic 등 자바에 익숙해졌고, 중복을 거부하고 책임을 나누어 메세지를 보내는 일이 자연스러워지면서, 이 코드가 객체지향스러운가? 를 고민하게 되었습니다.

     

    고작 3주 만에 제가 객체지향에 대해 다 알았다고 말할 수 없겠지만, 적어도 객체지향적인 코드가 무엇이며 왜 이것을 추구하는지, 객체지향이 꽤 자연스러워진 소중한 기간이었습니다.

    나는 개발을 좋아한다.

    개발을 하겠다고 마음먹은 지 1년 정도 되었는데, 무엇을 공부해야 하는지, 개발을 잘한다는 것이 무엇인지, 알고리즘 공부를 하고 있는 게 개발 공부를 하고 있는게 맞는 걸까? 같은 의심이 싹트고 있었습니다.

    그러던 중 우테코 프리코스를 통해 개발에 몰입하게 되고 재밌다고 느끼면서 '내가 개발을 좋아하는구나'라고 느끼게 되었습니다.
    제가 즐겁게 몰두할 수 있었던 데는 두 가지 정도 이유가 있었던 것 같습니다.

    • 강력한 동기부여
      우테코에 들어간다면 나도 유튜브로만 보던 우테코 테코톡을 할 수도 있고, 개발에 둘러싸인 환경에서 공부할 수 있는 기대 자체가 엄청난 동기부여가 되었던 것 같습니다. 위에서 언급한 객체지향의 사실과 오해라는 책은 워낙 유명해서 예전에 사두었던 책인데, 워낙 책도 안 읽었던 데다가 당시에 객체지향이 뭔지도 모르고 관심이 없어서.. 챕터 2 까지만 읽고 덮어두었었습니다. 그런데 동기부여가 생기니 개발이 재밌어지고, 챕터 2를 못넘어가던 그 책이 일주일도 안되어 다 읽혔습니다. 뿐만 아니라 다른 개발 서적에도 재미가 생겼고, 개발 블로그를 읽는 것도 꽤 흥미로운 일이 되었습니다.
    • 동료
      프리코스는 온라인으로 진행되지만, 우테코 담당자분들이 저의 코드를 보시고, 참가자들끼리 PR을 볼수 있으니 함께하고 있다는 기분이 들었습니다. 그러다보니 코딩 컨벤션을 지키는 것과 줄 바꿈 한줄 조차도 많은 고민을 하게되어 마치 하나의 작품을 만들어가는 것 같았습니다. 뿐만 아니라 제가 작성한 코드가 뭔가 아쉽다고 느껴질 때 다른 분들의 PR을 확인하면서 아이디어를 얻기도 하니, 혼자 공부할 때 보다 몇 배는 빠른 성장을 하고 있는 것만 같았습니다.

    프리코스를 진행하면서 개발이 재밌어지고, 객체지향이 궁금해지고, 하나를 이해하고 나니 다른 하나도 이해가 되는 선순환이 반복되고 있는 것 같았습니다.

    .

    글을 잘 쓰는 편이 아니라 두서없이 작성했는데요..

    .

    결론은 우테코 프리코스는 정말 배울게 많고 얻어갈게 많습니다. 지식을 주입시켜 주는 게 아니라 스스로 공부할 수 있게 방향을 잡아줍니다. 저는 그 방향을 따라가다 보니 객체지향을 알게 되었고, 알면 알수록 재밌어 지는데 저는 개발을 좋아한다는 사실까지 알게 되었습니다. ㅎㅎ

     

    감사합니다!

    댓글

Designed by Tistory.