반응형

 

비전공자 && 자바 어린이의 백엔드 프리코스 회고

 

 

 

 

 

1주차에 이어 2주차에도 많은 것을 배우고 느꼈다.

그도 그럴 것이 있는 시간 없는 시간 모으고 모아 열심히 몰입하고 있다.

 

그에 비해 얻은 것들을 곱씹을 시간은 적었기에,

기억이 휘발되기 전에 회고를 적어보려 한다.

 

프리코스 1주차 후기 👇👇

https://woojin.tistory.com/60

 

프리코스 1주차 회고 - 더도 말고 덜도 말고 1주차만 같아라~ (우아한테크코스 5기 백엔드 프리코

우테코 프리코스에 그야말로 '몰입'하고 있는 요즘이다. 합격하고 싶은 마음이야 두말할 것도 없지만, 합격 여부를 떠나 이 시간을 통해 올바르게 성장할 수 있다는 확신이 있다. 그래서 아주 마

woojin.tistory.com

 

 


기술적인 배움

 

메서드 분리

함수를 분리하는 것이 이번 주차의 요구사항 중 하나였다.

메서드를 분리하는 버릇은 원래도 (조금) 있었는데,

이번에는 메서드를 분리하는 것이, 어떤 효과를 불러오는지에 집중해보기로 했다.

 

- 코드의 재사용성 증가

작게 분리된 메서드는 다른 곳에서 재사용될 수 있다는 것을 발견했다.

남의 예시 코드가 아닌, 나의 코드에서 직접 발견한 것이라 훨씬 와닿았다.

 

여기서 고민되는 것이 있었는데,

새로운 유틸리티 클래스를 만들어, 서로 다른 클래스 내에서 반복되는 코드를 옮겨야 하나?

라는 것이었다.

 

코드의 반복을 줄일 수 있겠지만,

유틸리티 클래스가 객체지향적 관점에서 어떤 책임을 하는지가 애매했고

많은 클래스가 유틸리티 클래스에 의존하는 구조 또한 좋은 구조인지가 궁금했다.

(-> 관련 내용을 담은 커뮤니티 아고라 링크!(클릭))

 

 

- 코드의 가독성 증가

메서드가 작아질수록 네이밍이 수월했고, 가독성 증가로 이어졌다.

생각해보니, 메서드 규모가 클수록 여러가지 일을 하고 있을 확률이 높으니 네이밍이 어려운 것은 당연했다.

 

 

- 객체지향적인 설계

메서드를 분리하려고 노력하다보니, 자연스럽게 객체에 메시지를 보내게 되었다.

상태를 직접 가져와서 지지고 볶는 것이 아니라, 메시지를 보내고 그 응답을 사용하게 된 것이다.

 

 

 

함수별 테스트

함수별 테스트 또한, 이번 주차 요구사항 중 하나였다.

테스트 코드에 대한 경험이 많이 없어 두려웠지만, 일단 부딪혀보며 배우기로 마음을 먹었다.

 

- 유닛테스트와 통합테스트

미션 기본 파일에 주어진 코드를 보며, 기본적인 테스트 기능을 공부했다.

그리고 바로 테스트 코드를 구현하려했는데, 몇 시간이 지나도 구현이 되지 않았다.

알고 보니, 나는 '통합 테스트'를 구현하고 있던 것이었다..

 

테스트의 정의와 종류를 공부하면서, '유닛테스트'가 뭔지 알게 되었고,

작은 단위부터 테스트하며 테스트에 대해서 조금씩 배워나갈 수 있었다.

 

 

- 어노테이션 활용

BeforeEach를 사용해 각 테스트가 의존하지 않도록 구현할 수 있었다.

Nested로 테스트의 계층 구조를 설계할 수 있었으며,

DisplayName로 테스트 결과의 가독성을 높일 수 있었다.

 

 

- TDD의 첫 적용

테스트 코드를 작성하니, 기능 단위로 성취감을 느끼고

구현에 문제가 없는지 그때그때 확인할 수 있어서 너무 좋았다.

하지만 테스트 코드를 먼저 작성하는 TDD 방식은 너무 아득하게 느껴졌다.

 

미션 구현 중반부 쯤에서는 기본적인 테스트 코드 활용에 자신감이 붙었고,

테스트 코드를 먼저 작성해보자고 마음을 먹었다.

 

개념만 알고 있던 TDD를 직접 적용해보니,

먼저 작성한 테스트 코드가 문제 해결의 나침반이 되어준다는 느낌을 받았다.

 

하지만 해당 메서드에 대해 테스트 케이스를 완벽하게 구현할 수 있는 게 아니라면,

확실히 어렵겠다는 생각을 했다.

 

테스트 코드의 실력을 늘리면서, 차차 익숙해져보는 것을 목표로 해야겠다.

 

 

테스트 코드를 공부하면서,

한 번 잘 짜놓은 테스트 코드가 디버깅 시, 리팩토링 시 얼마나 많은 단계를 줄여주는 지 체감할 수 있었다.

이제 테스트 없는 개발은 불가능하다.. 초록 불빛에 중독되어 버렸기 때문..

보기만 해도 기분이 너무 좋네요..

 

 

가장 익숙한 언어가 된 자바

출처 : 데브경수(https://www.instagram.com/waterglasstoon/)

자바의 존재를 처음 알게된 것은 위의 짤이었다.

파이썬으로 개발 공부를 시작한 나는,

이유도 잘 모르고 여러 사람들의 농담 섞인 말에 휘둘려

자바가 꼰대 같고, 딱딱하고, 재미가 없을 거라는 편견을 가지게 되었다..

 

그래서 자바를 처음 공부했을 때는 다른 언어에 비해 두려웠다!

 

그런데 지금은..

불과 2주만에 자바는 나에게 가장 익숙한 언어가 되었다.

체계적으로 공부를 시작한 첫 언어이기 때문도 있는 것 같고..

 

이제는 어떤 문제를 해결하려고 생각하면,

자바 언어로 추상화된 객체를 먼저 구상하게 되고,

자료형과 메서드도 떠오른다.

 

이제 자바 없는 나를 떠올릴 수 없다(?)

자바를 꽉 자바야겠다. ㅋ

 

 

프리코스 커뮤니티

언급하지 않을 수 없다.. 정말 많은 도움을 얻고 있기 때문.

얼굴 한 번 본 적 없는 동료들과 함께 걸어가고 있는 기분이다.

 

- 피어 리뷰

이번 미션을 마치고는 피어 리뷰에 집중해보고 싶었다.

리뷰 경험이 거의 없는데다, 사실 남의 코드를 읽고 공부해본 경험도 많이 없다.

남의 코드를 읽는 것이 어색하다.

그래서 경험을 쌓기 위해서라도 피어 리뷰에 집중해보고 싶었다.

 

9~10명 정도의 피어 분들께 리뷰를 남긴 것으로 기억하는데,

리뷰가 거듭될수록 코드를 읽는 실력이 올라감이 느껴졌으며,

처음에는 보이지 않던 부분들이 보이기 시작했다.

 

피어 리뷰는 도움을 주면서, 동시에 나도 도움을 구해가는

정말 좋은 시간이었다.

 

 

- 북클럽 가입

지원자 한 분께서 기획해주신 북클럽에 가입했다.

읽고 있는 책에서 얻은 인사이트를 서로 공유하는 모임이다.

 

개발 관련 서적이 많은데, (나는 객체지향의 사실과 오해.. ㅋㅋ)

다른 분들은 글쓰기나 좋은 개발자가 되는 방법에 대한 고민이 담긴 책까지

다양한 책을 읽고 계신다.

 

북클럽까지 참여하실 정도로 우테코에 진심인 사람들과 교류할 수 있게 되어 기쁘다.

 

 

- 아고라

프리코스 커뮤니티 중 '깃허브 디스커젼'에는 아고라 카테고리가 있다.

프로그래밍 중 생각난 쟁점에 대해 공유하고,

다양한 의견을 나누는 장소이다.

 

정말 많은 것을 배우고 있다.

 

지식적인 부분도 많이 배웠지만,

참여자들이 의견을 교류할 때 갖추는 태도(예의, 설득 방식 등)도 배울 점이 많고,

어떤 쟁점들은 하나의 결론으로 모이지 않고, 다양한 의견이 존재한다는 것도 흥미로운 지점이었다.

 

 

 

 


인간적인 배움

 

지속가능한 페이스

프리코스를 시작하면서, 4주 동안 미친듯이 몰입하자고 마음을 먹었다.

사실 그 전 주부터 몰입했으니 총 5주인 셈이다.

 

그런데 이번 주는 약간의 번아웃을 겪었다.

아무리 용을 써도 머릿속이 하얘졌다.

 

생각해보니, 지난 2주 반 동안 한 순간도 쉬지 않았다..

다음 할 일을 위한 잠깐의 쉬는 시간 외에는, '쉬는 시간'이라고 규정된 시간 자체가 존재하지 않았던 것이다.

 

내가 좋아하는 러닝에서,

기록을 위해 가장 중요한 것은 '지속가능한 페이스'를 유지하는 것이다.

하지만 나는 10km를 달려야 함에도, 1km 밖에 가지 못 할 페이스로 전력질주를 하고 있었다.

잠시 모든 것을 내려 놓고, 잠깐의 휴식을 가졌다.

금방 회복했고 다시 몰입할 수 있었다.

 

4주는 짧지 않고, 남은 2주도 결코 짧은 시간이 아니라고 생각한다.

하루, 이틀만 바라 보고 내내 밤을 새기 보다는 (물론 4주차에는 그럴 예정 ㅋㅋ)

2주라는 기간이 최대의 퍼포먼스를 가질 수 있도록 노력해야겠다.

그리고 그것이 10개월이라는 긴 시간 동안 몰입하기 위한 연습이 되어줄 거라는 기대감도 든다.

 

 

요구사항에 집중하자! - 나만의 페이스

아 그리고 꼭 기록하고 싶은 것이 있는데,

요구사항에 집중하자는 것이다!

 

이번 코치들의 수다 타임(코수타)에서

남들이 말하는 어려운 키워드에 신경쓰지 말고

요구사항에 집중하라는 말씀을 해주셨다.

 

나도 모르게 TDD, 객체지향 생활체조 등..

남들이 얘기하는 키워드들을 따라가려고 애썼던 것 같다.

마치 공원에서 러닝할 때, 내 옆을 지나가는 고수를 따라가려고 스퍼트를 내듯이..

그럼 2~300m도 가지 못해 지치고 만다는 것을 안다.

 

나는 자바를 거의 처음 공부하는 자린이고,

객체지향이나 자료구조 수업도 들어보지 못한 비전공자라는 사실을 인정하자.

미션의 요구사항에 집중해서 프로그램이 의도하는 방향대로 성장하는 것을 목표로 하겠다!

는 다짐이 너무 중요한 것 같아 기록해둔다.

 

저 초록색 숫자가 뭐라고.. 이리 기분 좋은지..

 

 

 

마지막으로 미션 제출 소감에도 적었지만,

이번 한 주도 지원자들의 성장을 위해 힘써주신 많은 분들께 감사의 인사를 전하고 싶다.

덕분에 프로그래밍이 더 재밌어지고 있음에 너무 감사하다.

 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

java.lang.assertionerror: expecting code to raise a throwable.

 

위와 같은 에러가 발생했습니다.

 

이는 테스트 코드 중 예외 처리를 테스트하는 부분에서 발생하는 에러로,

에러가 발생되지 않았다는 뜻입니다.

 

 

그런데 분명 적절한 에러를 throw 했음에도 해당 에러가 발생하였습니다.

 

 

여러 번 문장을 읽어보다가,

try-catch 문을 삭제했더니 해결되었습니다.

 

catch를 통해 에러를 잡아서 처리해버렸기 때문에,

실제로는 에러가 발생하지 않았던 것입니다.

 

테스트 코드에서는 에러가 throw 되기를 기다리고 있었으니,

해당 오류가 발생한 것이었습니다.

 

 

감사합니다.

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

forEach는 throws를 할 수 없다.

static void checkIsOne(int number) throws Exception{
    if (number == 1) {
        throw new Exception("oh no");
    }
    System.out.println(number);
}

List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
list.stream().forEach(a -> checkIsOne(a)); // Unhandled Exception 발생!

forEach문 안의 메서드가 예외를 발생시키면,

Unhandled exception: java.lang.Exception 라는 에러 메세지가 출력됩니다.

 

일반 메서드에서 예외가 발생하면 throws를 사용하면 되었는데요,

forEach문에서는 throws 키워드를 적용할 수 없어 난감했습니다.

 

 

하지만 try-catch문으로 간단하게 해결할 수 있었습니다.

 

 

 

 

try-catch 사용!

예외를 처리하는 방법에는 대개 throws와 try-catch를 사용하는 방법이 있습니다.

throws는 상위로 예외를 보내는 것입니다.

 

static void checkIsOne(int number) throws Exception{
    if (number == 1) {
        throw new Exception("oh no");
    }
    System.out.println(number);
}

List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
// Unhandled Exception 해결
list.stream().forEach(a -> {
    try {
        checkIsOne(a);
    } catch (Exception e) {
        System.out.println(e);
    }
});

try-catch문은 예외를 직접 처리합니다.

forEach문 안에 try-catch를 사용하면, Unhandled exception이 사라집니다.

 

 


 

 

간단한 오류를 해결하면서,

throws와 try-catch의 차이에 대해 이해할 수 있었네요.

 

감사합니다.

 

 

 

 

 

 

 

반응형
반응형

 

 

추상이 도대체 뭔 소린지 모르겠는

코린이 && 자린이 &&  비전공자(== 나) 여러분께 바칩니다..

(지적은 언제나 대환영입니다.)

 

 

 

 

 

본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있습니다.

 

1. 인터페이스와 구현체가 무엇인가?  (List와 ArrayList의 차이) (클릭🔗)

2. ArrayList가 아닌 List 타입으로 선언하는 이유 (업캐스팅) (클릭🔗)

3. Set - HashSet, Map - HashMap 의 차이 (클릭🔗)

4. 추상클래스란? -> 본편

 

 

 

 


 

추상이란?

 

위키백과에서는 '추상화'를 아래와 같이 설명합니다.

 

"컴퓨터 과학에서 추상화(abstraction)는 복잡한 자료, 모듈, 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려 내는 것을 말한다."

 

이게 바로 이해가 되시나요?

 

뭔가 간추린다는 느낌은 알겠는데,

우리 일상에서 사용하던 추상이라는 단어의 뜻과는 많은 괴리감이 느껴집니다.

 

적어도 저는 그랬습니다.

 

 

이런게 추상화 아닌가요..?

(물론 이 '화'는 그림이고, 그 '화'는 속성의 변화를 의미하기에 다릅니다만.. 발음과 글자가 주는 느낌이라는 것이 있단 말입니다..)

 

 

프로그래밍을 공부하며 많은 부분에서 '추상'이라는 표현을 접했습니다.

객체지향의 추상화, 자바의 추상 클래스, 추상 메서드..

 

그렇게 공부하다가 자연스럽게 '추상'의 뜻을 이해하게 되었고,

위에 적힌 정의를 읽어봐도 어느정도 감이 잡히더라고요.

 

 

저는 '추상'이라는 뜻에 대해

1. 간단하게 설계 또는 간단하게 보여지는

2. '구체적'의 반대

두 가지 해석을 적용하고 싶습니다.

 

 

추상화라는 개념이 매우 중요하지만,

그만큼 넓고 추상적인 개념인 것 같습니다.(닉값 제대로)

따라서 위의 두 가지 해석으로는 많이 부족할 수도 있습니다.

 

하지만 저처럼 도통 이해가 안 돼서 넘어가는 것보다는 낫다고 생각합니다.

이해가 안 되는 초기에는 쉽게 이해하다가, 이해가 쌓일수록 본질적인 뜻을 파악할 수 있으리라 생각합니다.

 

 

아무튼 이런 뜻 풀이를 가지고,

추상 클래스, 추상 메서드가 무엇인지 알아보겠습니다.

 

 

 

 

 

 

 

 

추상 클래스, 추상 메서드

 

추상 클래스는, 추상 메서드를 1개 이상 가지고 있는 클래스를 뜻합니다.

 

그러니 '추상 메서드'를 이해하는 것이 더 중요하겠네요.

추상 메서드의 뜻은 '자식 클래스에서 반드시 오버라이딩해야 하는 메서드'입니다.

 

 

반대 관점에서 보면?

부모 클래스에는 구현되지 않고 선언만 되어 있는 메서드입니다.

자식 클래스에서 오버라이딩을 통해 직접 구현해야만 사용할 수가 있는 것입니다.

 

추상 메서드는 구체적으로 구현이 되어 있지 않습니다.

간단하게 설계만 되어 있으며, 구현은 상속 받은 클래스에서 직접 해야 합니다.

 

 

 

 

 

 

 

인터페이스와 추상 클래스

 

인터페이스는 추상 클래스에 속합니다.

인터페이스의 모든 메서드는 추상 메서드여야하기 때문이죠. (default, static은 예외)

 

따라서 인터페이스는 모든 메서드가 '선언'만 되고 '구현'은 되지 않은 껍데기 입니다.

설계도, 가이드와 같죠.

 

인터페이스를 구현하는 구현 객체는, 인터페이스에서 선언된 모든 추상 메서드를 '구현'해야만 합니다.

 

인터페이스로 규격을 간단하게 설계하고, (비구체적, 추상)

구현 객체에서는 규격에 맞게 메서드를 구현합니다. (구체적)

 

 

 

자바의 ArrayListList의 관계로 설명을 더해보겠습니다.

 

둘의 관계는 아래와 같습니다.

List(인터페이스) ---(구현)---> AbstractList(추상 클래스) ---상속---> ArrayList(클래스)

 

실제로 정의된 코드를 살펴보며

List 인터페이스는 리스트가 갖춰야 할 규격을 간단하게 설계했습니다.

List를 구현한 코드의 일부 - 구현되지 않은 추상 메서드들이 간단하게 설계되어 있다.

 

AbstractList 추상 클래스에서는 그중 일부를 구체적으로 구현했고, 일부는 추상적으로 남겨둡니다.

AbstractList를 구현한 코드의 일부 - add는 구현되었고, get은 추상 메서드로 남아 있다.

 

ArrayList 클래스에서는 모든 추상 메서드를 구체적으로 구현하고, 일부 메서드는 오버라이딩합니다.

ArrayList를 구현한 코드의 일부 - 추상 메서드로 남아 있던 get을 구현했다.

 

 

이것이 추상 클래스, 추상 메서드가 실제로 활용되는 방식입니다.

 

 

 

 


 

 

본 아티클을 통해 추상 클래스, 추상 메서드에 대한 이해가 더해지길 바랍니다.

또, 저처럼 추상의 뜻이 도통 이해되지 않던 자린이, 코린이도 추상의 개념을 조금은 이해해가길 기원합니다.

 

잘못된 부분이 있다면 단호한 지적 부탁드립니다.

감사합니다!!

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

(지적은 언제나 대환영입니다.)

 

 

본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있습니다.

 

1. 인터페이스와 구현체가 무엇인가?  (List와 ArrayList의 차이) (클릭🔗)

2. ArrayList가 아닌 List 타입으로 선언하는 이유 (업캐스팅) (클릭🔗)

3. Set - HashSet, Map - HashMap 의 차이  -> 본편

4. 추상클래스란? (클릭🔗)

 

 

 

 


Set과 HashSet, Map과 HashMap의 차이

 

Set<String> set = new HashSet<>();
Map<String, Integer> map = new HashMap<>();

위와 같은 코드를 자주 보셨을 거라 생각합니다.

 

여기서 한 가지 의문이 듭니다.

HashSet 객체를 Set으로 선언하는 거지?

HashMap 객체를 Map으로 선언하는 거지?

 

 

여기서 SetMap인터페이스입니다.

인터페이스는 실제로 구현되지 않은 추상메서드만 가지고 있습니다.

 

하지만 HashSetHashMap은 해당 인터페이스들을 구현(implements)한 클래스입니다.

이러한 클래스를 해당 인터페이스의 구현체, 구현 객체 라고 합니다.

 

 

비유하자면,

인터페이스는 Set(집합)으로서 갖춰야 할 규격, 지켜야 할 가이드와 같은 개념입니다.

HashSet은 그 규격에 맞춰 실제로 설계된 물건입니다.

 

 

(아래에서는 편의를 위해 Set만 언급하겠습니다. Map으로 치환해도 내용은 동일합니다.)

 

위와 같이 set 변수를 Set으로 선언하면,

Set 인터페이스에 선언된 메서드를 사용할 수 있습니다.

그리고 그 동작은 HashSet에서 구현된 로직을 통해 이루어집니다.

 

 

그런데, Set 인터페이스에는 없지만

HashSet에는 구현되어 있는 메서드가 있을 수도 있습니다.

 

그리고 Set 타입인 set 인스턴스는 그 메서드를 사용할 수 없습니다.

 

 

그럼에도 불구하고 setSet 타입으로 선언하는 이유가 무엇일까요?

아래에서 그 이유를 다뤄보겠습니다.

 

 

 

 

HashSet, HashMap이 아닌 Set, Map으로 선언하는 이유

 

바로 다형성 때문입니다.

 

다형성은 하나의 객체에 여러 가지 타입을 적용할 수 있는 것입니다.

 

사실 HashSet을 많이 사용하지만,

Set 인터페이스의 구현체에는 TreeSet, LinkedHashSet 등도 있습니다.

(당연히 아실 수도 있지만, 저는 몰랐습니다..)

 

Set<String> set = new HashSet<>();


public int getFirstValueOfSet(Set<String> set) {
	return set.어쩌구();
}

만약 위와 같이 구현된 코드에서,

HashSet이 아닌 TreeSet을 사용하고 싶다고 해봅시다.

 

그럼 아래와 같이 HashSetTreeSet으로 수정하면 됩니다.

Set<String> set = new TreeSet<>();


public int getFirstValueOfSet(Set<String> set) {
	return set.어쩌구();
}

 

 

하지만 아래 set 객체가 Set이 아닌 HashSet으로 선언되었다면?

HashSet<String> set = new TreeSet<>(); // 컴파일 에러 발생


public int getFirstValueOfSet(HashSet<String> set) {
	return set.어쩌구();
}

컴파일 에러가 발생합니다.

 

게다가 수정을 위해서는 HashSet을 전부 TreeSet으로 바꿔줘야 합니다.

TreeSet<String> set = new TreeSet<>(); // 변경 과정이 복잡하다


public int getFirstValueOfSet(TreeSet<String> set) {
	return set.어쩌구();
}

 

코드가 복잡할수록 이러한 문제도 더욱 심각해집니다.

 

 

그렇기에 setSet으로 선언하고,

인자로 받을 때도 Set 타입으로 받는 것이죠.

이렇게 상위 개념으로 선언하고, 하위 개념을 생성해 할당하는 것을

업캐스팅(Up-casting)이라고 합니다.

(반대로 업캐스팅된 객체를 하위 개념 타입으로 변환하는 것은 다운캐스팅입니다.)

 

 

이는 객체지향의 SOLID 원칙D(Dependence Inversion Priciple : 의존 관계 역전 원칙)와도 연관이 깊은 내용입니다.

관련한 내용은 깊고 중요해, 따로 찾아보시는 것을 추천드립니다.

 

 

 

 


 

 

 

본 편에서는 1, 2편의 내용을 Set과 Map에도 적용해보았습니다.

 

1, 2편을 읽지 않아도 대략적인 이해가 되리라 생각합니다만

이해가 어렵거나 보다 더 이해하고 싶으시다면,

1, 2편을 차례로 읽어보시길 추천드립니다.

 

1편 - 인터페이스와 구현체가 무엇인가?  (List와 ArrayList의 차이) (클릭🔗)

2편 - ArrayList가 아닌 List 타입으로 선언하는 이유 (업캐스팅) (클릭🔗)

 

 

 

 

마지막 4편에서는 추상클래스에 대해 가볍게 다뤄보겠습니다.

https://woojin.tistory.com/64

 

추상클래스란? 아니, 추상이란? - 무조건 이해되는 List와 ArrayList의 차이(4)

추상이 도대체 뭔 소린지 모르겠는 코린이 && 자린이 && 비전공자(== 나) 여러분께 바칩니다.. (지적은 언제나 대환영입니다.) 본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있습니다. 1.

woojin.tistory.com

 

이 '추상', '추상화'라는 개념이 프로그래밍에서 쓰이는 것와 일상에서 쓰이는 뜻이 너무 달라 저에게는 너무 어렵게 느껴졌습니다.

관련해서 느꼈던 점과 이해한 방식을 소개해보고자 합니다.

 

 

 

 

감사합니다!

 

 

 

 

 

 

 

 

반응형
반응형

 

 

10분만 이 글에 투자해주시면

ArrayList를 List로 선언하는 이유를 이해시켜드리겠습니다..

(지적은 언제나 대환영입니다.)

본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있습니다.

 

1. 인터페이스와 구현체가 무엇인가?  (List와 ArrayList의 차이) (클릭🔗)

2. ArrayList가 아닌 List 타입으로 선언하는 이유 (업캐스팅)  -> 본편

3. Set - HashSet, Map - HashMap 의 차이 (클릭🔗)

4. 추상클래스란? (클릭🔗)

 

 

 

 


ArrayList가 아닌 List 타입으로 선언하는 이유 (업캐스팅)

 

1편에서는 ListArrayList가 무슨 차이인지,

인터페이스와 구현체의 개념와 그 차이에 대해서 살펴보았습니다.

(해당 내용을 모르겠다면 클릭🔗)

 

 

List<String> stringList = new ArrayList<>();	// 1번
ArrayList<String> stringList = new ArrayList<>();	// 2번

이제 위 구문을 살펴보겠습니다.

 

 

stringList 변수는 ArrayList 구현체로 생성되었습니다.

ArrayList 클래스 구현 코드를 살펴보면, 아무 인자가 없을 때 작동하는 생성자가 존재할 것이고,

그것에 따라 ArrayList 객체를 생성했고, stringList에 할당시켰을 것입니다.

 

그런데, 어차피 ArrayList를 생성해서 사용할 것이라면

ArrayLIst 타입으로 선언하면 되지 않을까요? (1번)

굳이 List로 선언할 이유가 있을까요?? (2번)

 

하지만 2번을 사용하는 것이 널리 알려져 있습니다.

그 이유에 대해서 살펴봅시다.

 

 

Yo DJ~ spin that shxx~

 

 

 

 

1. List의 메서드는 문제 없이 사용 가능하다!

우선, List로 선언한 변수에 ArrayList를 구현체를 생성해 할당하면

List 안에 선언된 추상 메서드들을 ArrayList가 구현한 방식대로 사용할 수 있습니다.

 

이해를 돕기 위해 예시를 들겠습니다.

 

Listadd, size 라는 추상 메서드가 선언이 되었다고 가정하겠습니다.

그리고 ArrayListadd, size라는 메서드가 구현이 되었고,

추가로 addSize라는 메서드도 새로 구현이 되었다고 하겠습니다.

 

그럼 List 타입으로 선언된 stringListaddsize라는 메서드를 사용할 수 있습니다.

그리고 그것을 사용하면, ArrayList에서 구현한 방식대로 동작합니다.

 

하지만 여기서 문제가 발생하는데,

List에는 addSize라는 메서드가 선언되지 않았기 때문에,

stringListArrayListaddSize 메서드를 사용할 수 없습니다.

 

그렇지만, 대개 ArrayList에서 새로 선언한 메서드는 잘 사용되지 않고,

List 인터페이스에 선언된 메서드만으로 충분하기 때문에 큰 문제가 없다고 합니다!

 

 

 

 

2. (중요!) 다형성 부여 (+ 의존 관계 역전 원칙)

다형성이란 '하나의 객체가 여러 가지 타입을 가지는 것'을 의미합니다.

 

List<String> stringList = new ArrayList<>();


public int getFirstValueOfList(List stringList) {
	return stringList.어쩌구();
}

위 코드를 살펴보겠습니다.

stringListList 타입이지만, ArrayList로 구현되었습니다.

그런데, 자료의 추가, 삭제를 빠르게 하려고 LinkedList를 사용하고 싶어진다면 어떡할까요?

 

// List<String> stringList = new ArrayList<>();
List<String> stringList = new LinkedList<>();


public int getFirstValueOfList(List stringList) {
	return stringList.어쩌구();
}

구현체만 ArrayList에서 LinkedList로 변경해주면 끝입니다.

 

 

하지만, stringList의 타입이 List가 아닌 ArrayList였다면??

// List<String> stringList = new ArrayList<>();
ArrayList<String> stringList = new LinkedList<>(); // 컴파일 에러 발생


public int getFirstValueOfList(ArrayList stringList) {
	return stringList.어쩌구();
}

ArrayList 타입에는 LinkedList 구현체를 할당할 수 없어서 컴파일 에러가 발생합니다.

 

 

위와 같은 코드를 구현했다면,

코드에 보이는 ArrayList를 모두 LinkedList로 수정해야 합니다.

// List<String> stringList = new ArrayList<>();
LinkedList<String> stringList = new LinkedList<>();


public int getFirstValueOfList(LinkedList stringList) {
	return stringList.어쩌구();
}

 

코드가 복잡할수록 이 문제는 심각해집니다.

 

 

따라서 stringListList로 선언하고,

인자로 받을 때도 List로 받는 것입니다.

 

후에 stringList의 구현체가 변경되어도,

stringList와 관련한 메서드들을 수정할 필요가 없어지기 때문이죠.

 

이렇게 상위 개념으로 선언하고, 하위 개념을 생성해 할당하는 것을

업캐스팅(Up-casting)이라고 합니다.

 

(반대로 업캐스팅된 객체를 하위 개념 타입으로 변환하는 것은 다운캐스팅(Down-casting)이라고합니다.)

 

 

 

+ 추가내용)

이는 객체지향 SOLID 원칙D에 해당하는

의존 관계 역전 원칙(DIP : Dependency Inversion Principle)과도 연관이 있습니다.

 

저 원칙은 뜻이 되게 어려운데 (저에게는..)

저수준 모듈이 아닌 고수준 모듈에 의존해야 한다는 뜻을 가지고 있습니다.

 

즉, ArrayList가 아니라 List에 의존해야

다형성을 가질 수 있고, 다른 원칙을 위반하지 않을 수 있다는 것이죠.

관련 내용은 복잡하지만 중요해서, 추가로 찾아보기를 추천드립니다.

 

 

 


 

다음 아티클에서는

SetHashSet, MapHashMap의 차이에 대해서 다뤄보았습니다.

https://woojin.tistory.com/63

 

Set과 HashSet, Map과 HashMap의 차이 - 무조건 이해되는 List와 ArrayList의 차이(3)

(지적은 언제나 대환영입니다.) 본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있습니다. 1. 인터페이스와 구현체가 무엇인가? (List와 ArrayList의 차이) (클릭🔗) 2. ArrayList가 아닌 List 타

woojin.tistory.com

 

1, 2편 내용으로 충분히 이해되었을 내용이지만,

복습이 필요하시다면 읽어봐주세요.

 

감사합니다!

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

10분만 이 글에 투자해주시면

List, ArrayList, 인터페이스, 구현체 이해시켜드리겠습니다..
(지적은 언제나 대환영입니다.)

본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있습니다.

 

1. 인터페이스와 구현체가 무엇인가?  (List와 ArrayList의 차이) -> 본편

2. ArrayList가 아닌 List 타입으로 선언하는 이유 (업캐스팅) (클릭🔗)

3. Set - HashSet, Map - HashMap 의 차이 (클릭🔗)

4. 추상클래스란? (클릭🔗)

 

 

 

 

 


List<String> stringList = new ArrayList<>();

위 코드를 처음 보고 이런 생각이 들었습니다.

ArrayList<String> stringList = new ArrayList<>();

이렇게 바꿔야하는 거 아닌가?

 

어차피 ArrayList를 사용할 건데, 왜 타입은 List로 지정하는 거지?

이렇게 생긴 의문은 ListArrayList의 차이, List는 뭐였더라.. 등등 겉잡을 수 없는 의문 폭탄에 불을 붙였습니다.

 

 

 

누구에게는 상당히 쉬운 주제일 수 있겠으나,

자바 문법을 가볍고 빠르게 공부한 저에게는

전혀 이해가 되지 않는 문제였습니다.

 

하지만 이번 공부를 통해 인터페이스와 구현체에 관한 개념은 완벽하게 이해했다고 자부합니다.

관련해서 찾아보고 이해한 내용을 공유하고자 합니다.

 

 

 

 

 

 

Trust me, Follow me. ㅋㅋ

 

 

 


 

인터페이스(List)와 구현체(ArrayList)

 

List인터페이스이고, ArrayList클래스입니다.

그 차이를 알기 위해, 정의된 곳으로 가서 살펴볼 필요가 있습니다.

 

IntelliJ(또는 Eclipse)에서 Listimport한 후

List에 커서를 가져다 대고 cmd+B(ctrl+B)를 클릭하면, (또는 cmd + 마우스 좌클릭)

해당 클래스가 정의된 곳으로 이동합니다.

 

Let's go together~

List가 정의된 곳으로 가보자
List가 구현된 부분! interface로 선언되었음을 알 수 있다.
ArrayList가 구현된 부분..?

어라.. ArrayList는 이상하다..! 왜 두 번 구현되어 있지..? (사실 두 번보다 더 많다.)

게다가 classinterface로도 선언되지 않았습니다.

 

왜냐면, 해당 부분은 생성자를 구현한 부분이기 때문입니다.

위로 올라가면 ArrayList의 선언이 나옵니다.

ArrayListAbstractList를 상속받은 클래스입니다. AbstractList도 들어가봅시다.

 

implements List !!

그렇습니다.

결국 ArrayLisstList라는 인터페이스를 구현(implements)한 클래스입니다.

(중간을 매개하는 AbstractList 클래스는 맨 뒤 4번에서 다루겠으니, 잠시 잊어둡시다.)

 

여기서, 클래스(class)와 인터페이스(interface)의 차이를 짚고 넘어가겠습니다.

(필자는 둘의 차이를 정확히 알지 못했습니다.)

 

 

클래스(class) vs 인터페이스(interface)

클래스와 인터페이스는 모두 내부에 메서드를 가집니다.

하지만 클래스는 메서드의 body가 존재해서 그 내용이 구현된 반면,

인터페이스는 body가 존재하지 않습니다! (default, static 메서드는 예외)

 

여기까지는 필자도 이미 알고 있었지만, 왜 그렇게 되어 있는지는 몰랐습니다.

 

List 인터페이스 내부의 size 메서드 -> 설명만 주석으로 달려 있고, 구현이 안 되어 있다.
ArrayList 클래스 내부의 add 메서드 -> 구현이 되어 있다!

 

 

그것은 인터페이스와 클래스의 역할이 다르기 때문입니다.

 

아래에서는 List 인터페이스가 add, size 메서드 2개만 가지고 있다고 단순하게 가정하겠습니다.

 

List 인터페이스는 List가 갖춰야 할 기본 규격을 뜻합니다.

"List라고 하면, 자고로 add, size 메서드 정도는 있어야 해" 라고 알려주는 가이드와도 같습니다.

여기서, List안에 존재하는 add, size 메서드는 추상 메서드 라고 합니다.

구체적으로 기능이 구현된 메서드가 아니라, 그 존재만 추상적으로 선언된 것입니다.

 

ArrayListList 인터페이스를 구현(implements)한 클래스입니다.

List라는 규격에 따라, 실제로 add, size를 구현해서 사용하게끔 만들어졌다는 뜻입니다.

 

ArrayList 뿐만 아니라 LinkedList, VectorList 인터페이스 규격에 맞게 설계된 많은 클래스들이 존재합니다.

이런 클래스들을 LIst의 구현 객체 또는 구현체 라고 부릅니다.

 

ArrayList는 그중 배열의 성질을 활용하기 위해 만들어진 하나의 구현체일 뿐인 것이죠.

 

 

이렇게 우리는

인터페이스(List)와 구현체(ArrayList, 클래스)의 뜻을 이해했고,

List ArrayList가 어떤 차이를 가지는 지도 파악했습니다.

 

 

List<String> stringList = new ArrayList<>();

그렇다면, 정말 많이 볼 수 있는 위 구문에서

stringList 변수는 List로 선언되고 ArrayList로 생성된 이유는 무엇일까요?

 

 

 

다음 아티클에서 설명드리겠습니다!! (링크 👇)

https://woojin.tistory.com/62

 

ArrayList를 List로 선언하는 이유(업캐스팅) - 무조건 이해되는 List와 ArrayList의 차이(2)

10분만 이 글에 투자해주세요. ArrayList를 List로 선언하는 이유를 이해시켜드리겠습니다. 본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있다. 1. 인터페이스와 구현체가 무엇인가? (List

woojin.tistory.com

 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

우테코 프리코스에 그야말로 '몰입'하고 있는 요즘이다.

 

합격하고 싶은 마음이야 두말할 것도 없지만,

합격 여부를 떠나 이 시간을 통해 올바르게 성장할 수 있다는 확신이 있다.

그래서 아주 마음 편히 몰입하고 있다.

 

많은 지식을 머릿 속에 집어 넣고 있고, 많은 영감을 얻고 있다.

하지만 아쉽게도, 사유할 시간이 길지 않아 많은 것들을 흘려보내고 있다.

 

이번 우테코 프리코스는, 주차 별로 미션을 제출하면서 '소감'도 적어야 한다.

코치님들께서 설계하신 의도대로 운영되는지를 확인하기 위함도 있겠지만,

머릿 속에 들어온 지식, 과정에서 느낀 여러가지 것들을 한 번 씩 되짚어보라는 의미도 있을 것이라고 생각한다.

 

어쨌든 소감을 적어서 제출한 김에,

살을 조금 붙여서 미래의 나를 위한 회고를 적어보고자 한다.

아주 편~한 마음으로..

(사실 합격해서 이런 실력의 사람도 붙었구나.. 라는 메시지도 주고 싶은 마음이 간절하다.)

 

 

 


여태 자바를 공부했던 경험은

- 위키독스 '점프 투 자바' 1회독

- 인프런 스프링 무료 강의 따라하기

두 가지가 전부였다.

 

객체지향 개념도 아티클 몇 개를 찾아보고 타입스크립트, Nest.js 코드에서 임의로 적용해본 경험이 다였다.

완벽하게는 아니지만, 타입스크립트로 메서드를 분리하려고 노력해봤던 경험도 있었다.

 

 

그런 배경으로 시작해, 일주일간 어떤 것을 공부하고 어떤 것을 느꼈는지 적어보겠다!

 

 

 

자바 복습

그마저도 다 까먹은 자바 문법을 떠올리기 위해 점프 투 자바를 다시 1회독했다.

내용이 풍부하진 않지만, 빠르게 문법을 익히고 객체지향 개념을 겉핥기하기에 아주 좋았다.

다만 오래 함께할 기본서 한 개의 필요성도 느꼈다.

 

 

객체지향 공부

전공자라면 으레 듣는 객체지향 프로그래밍과 같은 과목을 수강하거나, 따로 공부해본 경험이 없었다.

구글링으로 아티클 몇 개 읽어본 어설픈 지식이 전부였다.

 

1주차 미션에는 객체지향 관련 규칙이 없었지만,

자바가 워낙 객체지향에 초점을 맞춘 언어이고, 앞으로의 미션에서 필요할 것이라고 생각해 객체지향을 공부했다.

 

객체지향의 사실과 오해 라는 책을 읽으면서 인터넷 아티클로 객체지향 개념(상속, 캡슐화, 추상화), SOLID 원칙 등을 찾아보는 식으로 공부했다.

 

객체지향의 사실과 오해 라는 책은 정말 좋았다.. 객체지향의 필요성, 각 개념에 대한 이해에 진짜 많은 도움이 되었다.

아직 책을 읽는 중이고, 각 개념에 대해 코드로 설명하지는 못할 것 같다.

프리코스를 진행하면서 꾸준히 공부해, 4주 후에는 객체지향을 마스터하겠다는 각오를 다진다.

 

 

프리코스 문제

1주차 프리코스는 7개의 문제를 해결하는 형식이었다.

각 문제들은 코딩테스트 형식을 띄고 있었다.

 

나는 코딩테스트 경험은 없고, 유튜브 강의로 공부하고 문제 조금 풀어본 경험만 있었다. (백준 실버4 수준)

 

알고리즘 지식이 부족해서 정확하지는 않을텐데,

아마 어려운 알고리즘을 사용하는 문제는 없었던 것 같다. (브루트 포스 정도..?)

 

다만 구현 로직 자체가 (나에게는) 엄청나게 까다로웠다.

특히 6, 7번을 처음 훑어봤을 때는, 일주일 안에 풀 수 있을까하는 걱정이 마음에 툭 얹혀버렸다 ㅋㅋ

 

하지만.. 하루종일 붙잡고 씨름하다보니

문제가 풀리긴 풀렸다!

 

자료구조에 대해서 지식이 부족하다 보니, 비효율적인 코드를 짠 것 같았다.

(사실 비효율적인지 판단하기도 쉽지 않았다.)

 

그래도 자바로 처음 '프로그래밍'을 해보았고,

내가 정말 어렵다고 생각한 기능을 어찌저찌 잘 구현해냈다는 것이 너무 기뻤다.

 

그리고 정말 신기했던 것이, 객체지향을 이론으로 공부하던 것들이 머리에 남아

코드를 짜는 내내 그것을 고려하게 만들었다는 것이다.

다만 이것이 객체지향의 여러 원칙들을 만족하는지 확인하기가 어렵다.

 

다가올 2주차부터, 1주차의 코드에 대해 토론하는 커뮤니티가 열린다.

그곳에서 다른 사람들은 코드를 어떻게 객체지향적으로 구현했는지 확인하고 싶은 마음이 크다!

 

 

기술적으로 배운 것들

1) 객체지향을 이론이 아닌 코드로 처음 적용

자바 문법만 공부할 때는, private, public이 어떤 의미인지 하나도 이해가 안 됐었다.

그런데 객체지향을 공부하면서 코드를 구현하다보니, 자연스럽게 그 의미가 파악이 되었다.

변하지 않는 멤버 변수에 private final static을 사용하면서 은닉화, 캡슐화 개념도 이해할 수 있었다.

 

2) 정규식 처음 사용
제한 사항을 예외 처리할 때, 정규식을 사용해서 간단한 로직으로 구현했다.

정규식을 처음 사용해봤는데,

글자수 제한, 한글만 가능, 영어 대소문자, 일부 특수문자 허용, 이메일 도메인 필수 등

다양한 제한 사항들을 하나의 문자열로 검증할 수 있는 강력함이 너무 신기했다.


3) List, Set, Map 객체에 대한 이해

List, Set, Map이 어떤 용도로 사용되는지는 알고 있었지만,

ListArrayList의 차이, 
좌변에 상위 타입으로서 선언해야 의존관계 역전이 일어나지 않는다는 것 등을 처음 알게 되었다.

 

관련해서 공부한 내용을 아티클 시리즈로 작성했다. (링크👇👇)

 

인터페이스와 구현체 - 무조건 이해되는 List와 ArrayList의 차이(1)

10분만 이 글에 투자해주시면 List, ArrayList, 인터페이스, 구현체 이해시켜드리겠습니다.. (지적은 언제나 대환영입니다.) 본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있습니다. 1. 인

woojin.tistory.com

 

ArrayList를 List로 선언하는 이유(업캐스팅) - 무조건 이해되는 List와 ArrayList의 차이(2)

10분만 이 글에 투자해주세요. ArrayList를 List로 선언하는 이유를 이해시켜드리겠습니다. 본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있다. 1. 인터페이스와 구현체가 무엇인가? (List

woojin.tistory.com

 

Set과 HashSet, Map과 HashMap의 차이 - 무조건 이해되는 List와 ArrayList의 차이(3)

(지적은 언제나 대환영입니다.) 본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있습니다. 1. 인터페이스와 구현체가 무엇인가? (List와 ArrayList의 차이) (클릭🔗) 2. ArrayList가 아닌 List 타

woojin.tistory.com

 

추상클래스란? 아니, 추상이란? - 무조건 이해되는 List와 ArrayList의 차이(4)

추상이 도대체 뭔 소린지 모르겠는 코린이 && 자린이 && 비전공자(== 나) 여러분께 바칩니다.. (지적은 언제나 대환영입니다.) 본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있습니다. 1.

woojin.tistory.com

 

 

4) 가변 문자열을 StringBuilder 타입으로 처리
문자열을 수정해야 되는 문제가 있었다.

처음에는 String → List<String> → String 의 순서로 변환해서 가변 문자열을 처리했는데,
List<String>에서 너무 많은 String 객체를 생성해야 하는 문제가 있었다.


후에 StringBuilder 타입을 활용할 수 있다는 것을 알게 되면서,

해당 문제 코드를 리팩토링하며 적용해 보았다.

전보다 훨씬 짧고 간결한 코드로 구현이 가능했다.

형변환 과정을 거치지 않아도 되고, 많은 String 객체를 구현할 필요도 없었다.

 

5. 이름과 점수를 가지고 있는 객체의 리스트 구현

이번 주차 미션을 진행하면서, 가장 뿌듯했던 순간이었다.

 

대략 [(이름, 점수), (이름, 점수)] 형식의 리스트가 필요했다.

처음에는 List<List<Object>> 타입으로 구현했는데, 값을 꺼낼 때마다 int나 String으로 캐스팅해 주어야 하는 문제가 있었다.

정렬할 때 sorted(Comparator.comparing()) 을 사용했는데, 그 안에 들어가는 코드도 무척 복잡했다.

 

관련 내용을 검색하면서, (이름, 점수)를 하나의 클래스로 묶는 방법에 대해 알게 되었다.

정확히는 이름, 점수를 클래스 변수로 갖는 새로운 클래스를 구현했다.

형변환의 문제는 당연히 사라졌고, 값을 꺼내거나 변경할 때 해당 클래스의 메서드를 사용하여 객체지향적으로 구현할 수 있었다.


6) 깃 + 코드 설계
기존에는 주로 혼자서 보는 용도로 커밋을 기록했는데,
이번 프리코스 1주차에는 협업 상황을 가정하고, 기능 단위 별로 커밋을 나눠보았다.

확실히 스스로 PR로 코드를 리뷰할 때 보기가 수월해졌다.

다음 주차에 커뮤니티를 통해 1주차 코드에 대해 리뷰를 받아볼 예정인데, 그때 빛을 발하지 않을까 생각하고 있다.

(근데 커밋을 너무 상세하게 나눠서, 다른 사람들은 어떻게 나눴는지 너무 궁금하다.)


또 기존에는 다짜고짜 개발부터 시작했었는데, 기능 설계를 먼저 하고 개발을 진행하는 방식을 연습해보았다.

처음에는 까다롭고 감을 잡기가 어려웠지만, 구현을 하면 할수록 설계도가 있어 올바른 방향으로 계속 구현할 수 있었다.

 

 

아쉬웠던 점, 부족한 부분

1) 자료구조와 자바 언어에 대한 깊은 지식

여러 언어를 돌면서 공부하다가, 자바를 처음 깊게 공부하고 있다. 공부할수록 자바에 대한 편견(꼰대같은 언어 등..)이 깨지고 그 매력을 알아가고 있다. 자바 생태계에 일원으로 안전하게 정착하고 싶다.

 

2) 객체지향에 대한 이해

객체지향의 개념에 대해서 하나하나 깨달아가는 과정이었다. 하지만 확실하게 이것이 객체지향적인 구현이다! 라고 정의하고 구현하지는 못하고 있다. 프리코스 기간 내내 객체지향을 열심히 공부해야겠다고 다시 다짐한다.

 

 

커뮤니티

이번 우테코 프리코스는 슬랙깃허브를 통해 커뮤니티를 운영한다. 깃허브 커뮤니티는 2주차부터, 1주차 미션 코드에 대해서 진행되기 때문에, 1주차에는 슬랙만 운영되었다.

그런데, 정말 많은 사람들이 자발적으로 정보를 공유하고 서로의 성장을 응원하고 있었다.

어느 필드에서 이렇게 경쟁자끼리 서로의 성장을 응원하고 도움을 나눌 수 있을까 싶었다

정확히는 경쟁보다는 상생, 같이 성장한다는 생각이 더 지배적인 것 같다.

지식 공유의 가치를 아는 사람들과 잘 설계된 미션을 함께 공부하는 시간이 너무 소중하게 다가왔다.

 

 

우테코 너무 가고 싶다..

입에 발린 소리일까봐 미션 소감에는 적지 않았는데,

정말 내가 꿈꾸던 교육 방식이 그대로 현실이 된 느낌이었다..

 

어려서부터 고민 없이, 소통 없이 암기하는 교육 방식이 너무 맞지 않았다.

때문에, 중고등학교 시절에는 책과 인터넷 강의로 독학을 했다.

대학에 와서도 이어지는 주입식 교육이 버거웠고,

다양한 분야를 돌면서 혼자서 공부해왔다.

 

주도적으로 공부하는 것은 늘 즐거웠으나,

치명적인 문제가 있었다.

 

좋은 환경을 조성하기가 어렵다는 것이다.

 

스스로 동기를 부여할 수 있고,

스스로 찾아보고 이해할 수 있어도,

가끔 잘못된 방향으로 나아갈 때 잡아줄 존재가 없고

과정을 함께 이겨낼 든든한 동료도 없다는 것이 늘 힘들었다.

 

 

하지만 고작 프리코스 1주차만 경험했음에도,

많은 고민이 해소되는 기분이 들었다.

 

학습의 방향, 목적지가 주어진다.

하지만 두 발로 걸어갈 지, 네 발로 기어갈 지, 자전거를 타고 갈 지는 스스로 정해야 한다.

과정에서 어느 방법이 효율적일지 같이 고민하고, 힘들 때 서로에게 기댈 동료가 있다.

 

만약 우테코 본 과정에 합격해서

크루원들과 대면하고 가까워져서 의지할 수 있는 관계가 된다면,

20년을 공부하면서 느꼈던 갈증이 해소될 수 있겠다는 생각을 했다.

 

 

 

너무 뿌듯했던 순간..

 

 

마지막으로, 많은 사람들이 이런 좋은 경험을 할 수 있게 힘써주신

많은 코치님들께 진심으로 경의를 표합니다..

남은 주차도 많이 배우고 성장하겠습니다.

 

 

다음 주도, 더도 말고 덜도 말고 이번 주차만 같이

많은 것을 배우고 느끼는 한 주로 만들 것이다.

 

회고 끝~!

 

 

 

 

 

 

반응형

+ Recent posts