우아한테크코스 프리코스 - 1주 차 회고

1주 차를 마친 나

 

순식간에 1주가 지나갔다 허허

이것저것 많이 시도하면서 프리코스 적응하느라 시간이 녹았다,,,

일주일 동안 어떤 결과물을 내었을지 궁금하다면 아래 링크를 클릭해보죠!🙇🏻‍♀️

https://github.com/woowacourse-precourse/java-calculator-8/pull/544

 

[문자열 덧셈 계산기] 임지현 미션 제출합니다. by Jiihyun · Pull Request #544 · woowacourse-precourse/java-cal

▶️️ 흐름 구분자 & 양수로 된 문자열을 입력한다. 구분자를 기준으로 분리한 숫자들을 모두 더한다. 덧셈 결과를 반환한다. 📝️ 기능 목록 ▪️ 입력 기능 구분자와 양수로 구성된 문자열

github.com

 

이번 주 목표

1주 차 목표를 한 마디로 표현해 보자면, 당연시하게 여기던 것들에 대해 의심해 보는 것이다!

객체지향, 자바 등 안다고 생각한 것들이 사실은 알고 있는게 아니였고,,이로 인해 다시 학습하며 필요성을 이해했다.

 

10/14 (화) Day 1

오늘의 도전

  • 미션 요구사항을 막연히 따르기보다, 맥락과 의도 생각해 보기

1. 많은 버전 중 Java 21을 사용하는 이유가 뭘까?

미션 요구사항 중 하나는 Java 21 버전을 사용하는 것이었다.

지금까지는 자바 버전을 선택할 때 단순히 "최신이면서도 안정적인 버전(Long-Term Support) 버전을 쓰면 되겠지”라고 생각했지만, 명확한 이유 없이 선택한 것에 대해 마음이 걸렸다.
따라서 미션 구현에 앞서 ‘왜 Java 21이어야 하는가?’라는 질문을 스스로 던지고 탐구해 보았고,

자바 버전별 특징을 비교하며 LTS 주기, 주요 기능, 호환성 등을 살펴봄을 통해, 현업 환경과의 연계성, 도구 호환성, 성능 등이 자바 버전 선택에 있어 이유가 될 수 있음을 이해했다.

이 내용을 바탕으로 미션 요구사항이 Java 21 버전인 이유를 주제로 토론 게시판에 공유하여 이야기를 나눠보고 싶었지만, 이미 관련 주제가 올라와 있어 댓글로 내 생각을 정리해 남겼다.

 

이 과정을 통해 앞으로 자바 버전 선택에 있어 스스로 판단할 근거를 갖출 수 있었다!

 

2. 컨벤션을 지정하면 어떤 이점이 있지?

[코드 컨벤션]

미션 요구사항으로 Java Style Guide를 준수하여 코드를 작성할 것이 명시되어 있었다.

처음에는 “보기 좋은 코드를 만들기 위한 규칙이겠지” 정도로 생각했지만, 요즘IT의 「개발자에게 ‘코드 스타일’ 왜 중요할까?」 글을 통해 코드 스타일은 미적 기준이 아니라 협업 효율과 생산성을 결정짓는 개발 문화의 핵심 요소라는 점을 알게 되었다.

 

이 내용을 학습하며 프리코스 이전에 참여했던 프로젝트가 떠올랐다...

그때는 컨벤션을 맞추지 않아 코드 스타일이 제각각이었고, 새로운 기능을 추가하거나 버그를 수정할 때 각자 작성한 코드가 뒤섞여 읽기 어려웠었다. 이 경험을 떠올리며, 코드 컨벤션이 단순한 형식이 아니라 협업 품질을 유지하기 위한 약속이라는 점에 공감할 수 있었다.

앞으로는 개발을 시작할 때마다 컨벤션을 먼저 정의하고, 팀이 같은 기준 위에서 협업할 수 있도록 노력해야겠다.

 

한편, Java Style Guide를 직접 살펴보니 지켜야 할 규칙이 상당히 많아 모든 항목을 일일이 인지하며 작성하기가 어려웠다.

이를 해결하기 위해 IntelliJ의 코드 스타일 자동 적용 기능을 활용하는 방법을 찾아 학습했고, 해당 내용을 커뮤니티의 ‘함께 자라기’ 게시판에 공유했다.

많은 분께서 공유해 줘서 고맙다는 댓글을 달아주셨고, 이에 힘입어 앞으로도 배운 내용을 글로 정리하며 함께 성장해야겠다는 동기를 얻었다 🥹

 

[커밋 컨벤션]

AngularJS Commit Conventions를 학습하며 구조화된 커밋 메시지의 필요성에 대해 고민했다.

AngularJS 컨벤션 문서를 읽어봄으로써, 구조화된 커밋 메시지는 코드 변경 의도 빠르게 알리기, 배포 버전 관리 등 협업을 위한 정보 전달 수단임을 알 수 있었다.

  • 명확한 변경 사항 전달: 각 커밋이 무엇을 변경했는지 명확하게 전달되어, 코드 리뷰와 협업이 용이해진다.
  • 자동화 도구와의 호환성: 구조화된 커밋 메시지는 자동화 도구와 쉽게 통합되어, 릴리스 노트 생성, 버전 관리 등에서 일관성을 유지할 수 있다.

학습 과정에서 특히 스코프(scope)를 어떻게 설정할 것인가에 대해 많이 고민했다.

AngularJS 컨벤션에서는 스코프를 “커밋이 영향을 미치는 코드의 영역을 명사 형태로 표현하는 단위”라고 설명하며, 생략 가능하다고 한다. 하지만 이 단위가 너무 세밀하면나중에 관리가 어려워질 있다고 생각했.

예를 들어 클래스명이나 함수명을 스코프로 사용하면, 이름이 바뀌었을 과거 커밋 히스토리를 읽으며 맥락이 끊길 있지 않을까? 

따라서 세부적인 변경 내용은 subject body에서 설명하고, 스코프는 model, view, controller처럼 코드의 계층 단위로 표현하는 것이 적절하다 판단했다. 접근은 리팩터링이 일어나도 의미가 변하지 않으며, 커밋 히스토리를 이건 모델 수정이구나처럼 한눈에 파악할 수 있다.
다만 이는 나 개인적인 판단이기에, 협업 환경에서도 유효한 기준이 될지는 검증이 필요하다고 생각하여 미션 제출 기한이 지나면 코드 리뷰를 통해 단점 개선점에 대해 의견을 나누며 나은 기준을 세워가고자 한.

 

느낀점

오늘은 전반적인 요구사항에 대해 학습하느라 기능 구현을 못했다.

그래도 막연하게 필요하다고 느끼지만 왜 필요한 지 설명할 수 없는 필요성을 제대로 학습할 기회를 얻어서 좋았다.

내일은 미션 구현해야지!

 

10/15 (수) Day 2

오늘의 도전

  • 기능 구현 시 AI 사용하지 않기
  • 프로그램 흐름 → 요구사항 → 명세화 → 설계 나만의 프로세스 확립
  • 행동이 상태를 결정하도록 ‘책임 주도 설계’ 하기

1. 기능 목록 작성

기능 목록을 작성해야 하는데, 어떤 내용을 적어야 할 지 고민이 많았다.

그래서 읽는 대상부터 정했다.

프로그램을 실제로 사용할 클라이언트를 주요 대상으로 두고,
프로그램을 처음 접했을 때 “프로그램이 어떤 일을 하는지”를 한눈에 이해할 수 있도록 하는 데 초점을 맞췄다.

 

이후 노트에 프로그램 흐름 → 요구사항 → 명세화 → 설계순으로 작성해보았다.

흐름을 이해하고, 반드시 구현해야 하는 요구사항과, 요구사항을 혼동없이 구현하기 위한 명세화 마지막으로 명세화한 것을 기반한 설계가 이어지면 나 스스로 이해가 잘 돼서 기능 목록을 꼼꼼히& 비개발자도 이해하기 쉽게 작성할 수 있을 것 같아서 해당 순서를 시도해봤다.

 

  • 그래서 어떻게 작성했냐면?
    • 구조화: 기능을 입력(Input) / 비즈니스 로직(Business) / 출력(Output) 단위로 구분해 작성했다.
      프로그램의 흐름을 반영함으로써, 프로그램이 어떤 순서로 동작하는지를 자연스럽게 파악할 수 있었다.
    • 추상화: 코드 세부 구현이 아닌 비즈니스 기능 단위로 기술함으로써, 리팩터링이나 구조 변경에도 기능 목록의 의미가 변하지 않도록 했다.
    • 명확화: 모호한 요구사항을 내 나름대로 해석하여 명세했다.
      프로그램에 생각지 못한 예외 상황들이 발생하지 않도록 할 수 있었다.

2. 미션 구현하기

미션을 구현하기에 앞서, 『객체지향의 사실과 오해』를 읽으며 객체 지향적인 코드가 필요한 이유 대해 학습했다.

책의 절반 이상인 part 5까지 읽으며 느낀 점은, 객체 지향의 핵심은 “변화에 유연하게 대응할 수 있는 구조”라는 점이다!

객체지향은 프로그램을 협력하는 객체들의 집합으로 보고, 객체가 자신의 상태를 스스로 관리하도록. 이때 객체의 상태를 행동 뒤로 감추는 캡슐화 객체의 자율성을 높이고, 협력을 단순하고 유연하게 만들어 준.

 

책에서는 객체 지향적인 설계를 할 수 있도록, 행동이 상태를 결정하는 '책임 주도 설계'를 강조한다.

이에 위 사진처럼 어떤 행동들이 필요한 지 먼저 생각하고, 이후 이 행위를 수행할 객체를 결정했다.

 

설계를 마친 후에는 기능 구현에 들어갔다.
1차 구현은 AI 사용 하지 않는 것을 목표로 했기에, 막히는 부분은 구글링을 통해 해결했다.

하지만 중간중간 막히는 부분은 사고의 흐름을 남기기위해 노션에 기록해 두었다.

 

Stream, 이스케이프 문자 등 이 부분은 차차 학습해야겠다!!

 

계산 기능에서 덧셈 범위를 BigInteger까지 고려해야 할지 고민이 많았다.
BigInteger는 이론적으로 오버플로우가 발생하지 않아 안정성이 높지만, 연산 속도가 느리고 메모리 사용량이 많다는 단점이 있기 때문이다.

이 때 나는 내가 구현하고자 하는 계산기의 목적을 떠올렸다.
금융·통계·과학 계산처럼 정밀도가 중요한 분야가 아니라, 아이폰 기본 계산기처럼 일상생활에서 사용하는 단순한 사칙연산 중심의 계산기말이다.
따라서 무제한 크기 정수를 다루는 BigInteger까지 고려하는 것은 프로그램의 목적에 비해 과도하다고 판단했기에,
long 범위 내에서 오버플로우를 감지하고 예외를 처리하는 방식을 선택했다.


기술 선택에 있어 절대적인 기준이 존재하는 것이 아니라, “무엇을 만들고자 하는가”에 따라 달라진다는 사실을 실감했다.
즉, 더 안전한 방법이 반드시 더 좋은 방법은 아니며, 프로그램의 목적에 맞게 선택하는 것이 중요하다는 점을 배웠다!

 

느낀점

오늘은 1차 구현을 마쳤다.

어느정도 책임을 분리하고 들어간 것 같은데, 막상 구현하니 책임이 덜 분리되었는지 컨트롤러 계층에도 커스텀 구분자 여부를 확인하는 비지니스 로직이 생겨버렸다..ㅎㅎ

내일 리팩토링 해봐야겠다!

 

10/16 (목) Day 3

오늘의 도전

  • 리팩토링 하기
  • 테스트코드 작성하기
  • 기능 목록 업데이트

하고자 했던 목표는 많았지만, 오늘 하루종일 리팩토링만 했다~;;;;;;

먼저 무엇을 했는지부터 공유하고, 개선할 점은 느낀점에 적어야지.

 

1. 컨트롤러 계층에 비지니스 로직 제거

    private boolean hasCustomDelimiter(String value) {
        return value.startsWith("//") && value.contains("\\n");
    }

 

이 로직이 컨트롤러에 있었는데,, 거슬렸다.

왜 거슬렸는지 생각해보니 이 로직은 컨트롤러 계층과 관련이 없는 비지니스 로직이기 때문이었다.

MVC 패턴에 대해서 학습하면서 답을 얻을 수 있었다.

=> controller는 view와 model을 연결하는 역할을 하므로 비지니스 로직이 있으면 안됨!

 

따라서 이 로직을 model에게 부여하려고 노력했고,

그 결과 구분자 관련 책임을 지닌 Delimiter 클래스와, 표현식을 파싱하는 책임을 지닌 ExpressionParser 클래스를 추가로 생성하였다.

  • Delimiter Enum
    • 구분자들 넣고, 커스텀 구분자인지 파악 메서드, 인덱스 및 길이 파악 메서드 추가
    • 왜? 구분자 관련 매직넘버들이 여러 클래스에서 사용되고 있었기 때문
    • 결과: 매직넘버 제거 & 구분자 관련 변경사항 생길시 구분자 enum만 변경하면 됨
  • ExpressionParser Class
    • 커스텀 구분자가 있을 시, 커스텀 구분자 포맷 제거한 표현식 반환 메서드 추가
    • 왜? NumberExtracter가 커스텀여부에 따라 바뀌는 건 자신의 본래 책임(숫자 추출)을 넘어서 “입력 규칙을 해석하는” 책임까지 떠안고 있었기 때문
    • 결과: 파싱하는 부분 테스트 가능해짐

 

2. 의존성 주입

Calculator calculator = new Calculator(new NumberExtractor()); 이런식으로 의존성을 new로 주입으로 했을 때 단점에 대해 알아보았다.

  1. 테스트하기 힘듦: Calculator나 NumberExtractor를 mock이나 stub으로 교체할 수 없다.
    • Calculator 객체 생성 시 자동으로 NumberExtractor 의존성이 고정 되기 때문에, 다른 NumberExtractor 구현체(ex. RegexNumberExtractor, CsvNumberExtractor)로 변경할 수 없게 된다.
  2. 결합도 증가
    • Calculator가 NumberExtractor의 구체 클래스를 알고 있어야 하므로, 두 클래스가 강하게 결합된다.
      만약 NumberExtractor가 다른 구현체로 교체되어야 하면, Calculator 코드도 수정해야 한다.
      OCP(개방-폐쇄 원칙) 위반
  3. 재사용성 낮음
    • 마찬가지로, Calculator 객체 생성 시 자동으로 NumberExtractor 의존성이 고정 되기 때문에 확장성이 떨어져 재사용이 어렵다.

정리하자면 해당 객체가 상태를 가지거나, 외부 리소스에 접근하는 경우(파일, DB, 콘솔 등 시스템 리소스)에는 생성자 주입으로 의존성의 관리하는 것이 더 유연하다는 것을 배웠다!

 

느낀점

리팩토링에 하루를 쏟고, 계획했던 다른 목표들을 수행하지 못해 아쉬움이 남았다.

이에 왜 이렇게 시간이 오래 걸렸는지 리팩토링 습관을 점검해 보았다. 그 결과, 한번에 너무 많은 변경을 하려 했고 리팩토링 목표가 모호했다는 문제를 파악할 수 있었다. "더 좋은 코드로 개선할 수 있을 것 같은데?"라고 막연히 목표를 넓게 잡은 점과, 책임 분리, 의존성 주입, 가독성 개선 등 여러 가지를 신경 쓰고 동시에 적용하려 했다. 결국 인지 부하가 커지면서 리팩토링의 방향을 잃고, ‘무한 개선 루프’에 빠지게 되면서 하루가 금세 지나가 버린 것이다🥲

앞으로는 리팩토링 번에 모든 고치려 하지 않고, 구체적인 목표를 세우고 하나씩 개선해 나가려 한다. 어떤 부분을, , 어떻게 바꿀 것인가 명확히 정의하고, 번에 하나의 개선만 시도하는 방식을 시도해보자!!

 

이후 커뮤니티 토론하기를 둘러보다가, 나와 비슷한 분들을 발견했고 반가운 마음에 댓글을 달았다 ㅎㅋㅎㅎ

 

경험을 공유하는 과정에서 생각이 정리되었고, 비슷한 고민을  사람들의 경험 노하우를 들으며 앞으로의 리팩토링 방향을 구체적으로 세울 있는 실마리를 얻을 수 있었다👍🏻

 

10/17 (금) Day 4

오늘의 도전

  • 테스트 코드 작성하기

1. 테스트 코드 작성

어느정도 기능 구현이 완료되었고, 더이상 구조가 크게 바뀔 것 같지 않아 테스트 코드 작성을 시작하였다.

해피케이스, 예외케이스 모두 작성하면서 프로그램의 안정성을 확인하였고,
JUnit5의 @ParameterizedTest를 활용하여 테스트 코드의 중복을 막을 수 있었다!

 

▪️ 테스트가 알려준 리팩토링의 필요성

public ExpressionInfo parse(String expression) {
        if (Delimiter.isCustom(expression)) {
            String delimiter = delimiterExtractor.extract(expression);
            String delimiterPattern = Delimiter.COMMA.getValue() + "|" + Delimiter.COLON.getValue() + "|" + Pattern.quote(delimiter);
            String parsedExpression = parseCustomFormat(expression);
            return new ExpressionInfo(parsedExpression, delimiterPattern);
        }
        String delimiterPattern = Delimiter.COMMA.getValue() + "|" + Delimiter.COLON.getValue();
        return new ExpressionInfo(expression, delimiterPattern);
    }

    private String parseCustomFormat(String expression) {
        int indexOfSuffix = Delimiter.CUSTOM_SUFFIX.getIndexIn(expression);
        return expression.substring(indexOfSuffix + Delimiter.CUSTOM_SUFFIX.getLength());
    }

 

테스트 코드를 작성하던 중, parse(String expression) 메서드가 여러 책임을 동시에 지고 있음을 확인했다.

파싱하는 것을 테스트하기에는 문자열 파싱구분자 처리 로직이 뒤섞여 있었던 것이다.

이를 계기로 기능을 분리하고 각 메서드가 한 가지 역할만 수행하도록 리팩토링을 진행하였다.

public String parse(String expression) {
        if (Delimiter.isCustom(expression)) {
            return parseCustomFormat(expression);
        }
        return expression;
    }

 

한결 가벼워진 코드,,ㅎ

테스트 코드를 통해 책임을 분리한 것에 대한 피드백을 받을 수 있어 좋았다.

TDD로 진행한다면 책임 분리한 것에 대해 더 빠른 피드백을 받을 수 있을 것 같은데,,진입장벽이 높다.

그래도 2-3주차에는 꼭 시도해 보는 걸로 하자! 도전도전도전도전

 

2. 기능 목록 업데이트

2일차에 많은 고민을 하고 기능 목록을 작성해서 인지, 기능 목록에서 추가하거나 수정할 부분이 많이 없었다.

메서드나 클래스명, 리턴 타입 등을 기능목록에 작성해두지 않았던 추상화 덕분이 아닐까...!? 한다.

그래도 좀 더 이해가 잘되었으면 하는 마음에 프로그램 흐름 및 예외 상황에 대한 예시들을 추가하였다.

 

3. DTO 토론 참여

 

프리코스 들어가기에 앞서 세웠던 목표 중 하나! 기술 토론에 참여하였다.

다들 의견이 비슷하여 뜨거운 논쟁은 없었지만, 그래도 내 생각을 근거를 가지고 전달할 수 있어 뿌듯했던 경험이었다.

DTO에 대해 고민하며 블로깅을 해두었던 게 빛을 발휘하다니..!!
앞으로도 메타인지 열심히하고 기록해두어야겠다.

 

느낀점

테스트 코드를 몰아서 작성하다보니, 시간을 생각보다 오래 걸렸다.
그래도 매번 콘솔에 시나리오 입력없이, 버튼 하나로 언제든 원할 때마다 검증할 수 있다는 점을 생각하면 더욱 꼼꼼히 작성해야지...

다음 미션부터는 TDD든 기능 구현&테스트 같이 하든지 새로운 시도를 해봐야겠다!

 

10/18 ~ 19(토, 일) Day 5, 6

오늘의 도전

  • 퍼사드 패턴 적용
  • PR 제출!!!!!!!!!!!

1. 끝이 없는 리팩토링

▪️ 퍼사드 패턴

각각 객체에게 책임을 부여한 후, 덧셈을 수행하기 위해 이 객체들을 협력시킬 객체가 필요했다.

따라서 Calculator라는 객체를 만들고, sum 메서드 안에서 각 객체들을 호출하며 덧셈을 수행하도록 하였다.

 

public class Calculator {

    private final DelimiterExtractor delimiterExtractor;
    private final ExpressionParser expressionParser;
    private final NumberExtractor numberExtractor;

    public Calculator(DelimiterExtractor delimiterExtractor, ExpressionParser expressionParser,
                      NumberExtractor numberExtractor) {
        this.delimiterExtractor = delimiterExtractor;
        this.expressionParser = expressionParser;
        this.numberExtractor = numberExtractor;
    }

    public long sum(String value) {
        String delimiter = delimiterExtractor.extract(value);
        String expression = expressionParser.parse(value);
        Numbers numbers = numberExtractor.createNumbers(expression, delimiter);
        return numbers.sum();
    }
}

 

이후 이렇게 코드를 구현해도 되는지 의문이 들어 GPT한테 물어보았다...

그런데...!

알고보니 내가 작성한 코드가 퍼사드 패턴이라고 했다.

퍼사드 패턴은 라이브러리에 대한, 프레임워크에 대한 또는 다른 클래스들의 복잡한 집합에 대한 단순화된 인터페이스를 제공하는 구조적 디자인 패턴입니다.

출처: https://refactoring.guru/ko/design-patterns/facade

 

  • 책임 과도 여부 판단에 대해
    • Calculator가 직접 구분자나 표현식을 추출하는가? ❌
    • 단순히 각 객체들을 조합하고 덧셈 결과를 반환하는가 ✅
    • 따라서 Calculator의 책임은 “계산 프로세스의 조립과 실행”이며, 이는 SRP(단일 책임 원칙)를 위반하지 않는다.
  • Controller에서 수행하는 건?
    • 컨트롤러는 입력과 출력의 흐름을 제어하는 책임만 가져야 한다.
    • 컨트롤러가 직접 모든 파서를 호출하면, 비지니스 흐름이 노출되는 것이 아닐까..?

따라서 위 클래스를 최종 코드로 선택했다.

다만, 이 클래스는 도메인 로직을 조합하는 역할이기 때문에 Calculator에서 CalculatorFacade로 이름을 변경하였다.

결과적으로 입출력과 분리된 퍼사드 클래스를 통해 통합 테스트를 손쉽게 수행할 수 있었다.
의도하지 않았지만... 책임 중심 설계 과정에서 자연스럽게 퍼사드 패턴이 도입된 점이 흥미로운 경험이었다!

 

▪️ 문자열과 문자의 차이에 대해 깨닫다

제출 전 미션 요구사항을 다시 읽어보면서 커스텀 구분자 조건에 대해 잘못 해석하고 있었다는 사실을 깨달았다.

미션에서는 커스텀 구분자로 문자만 허용하였는데, 나는 문자열과 문자의 차이를 명확히 인지하고 있지 못해 '**' 이런식으로 문자열을 구분자를 지정해도 허용한 것이다.

 

문자열과 문자의 차이에 공부하면서, 문자열과 문자의 개념을 보다 깊이 이해하게 되었다.
Java는 기본적으로 UTF-16 인코딩을 사용하며, 유니코드(Unicode)는 다양한 문자 집합을 지원한다.
UTF-16에서는 대부분의 문자가 하나의 16비트 코드 유닛으로 표현되지만
이모지나 일부 특수문자 등은 두 개의 코드 유닛(surrogate pair) 으로 표현된다.

 

“길이 1인 문자열”이 반드시 “하나의 문자”를 의미하지 않는다는 점을 배웠고,
문자 처리 로직을 다룰 때는 인코딩과 코드 유닛의 개념까지 함께 고려해야 함을 깨달았다.

하지만 나는 이모지 등을 구분자로 사용하지 못하게 문자 검증로직을 길이를 통해 검증하였다,,ㅎ

그래도 나름 책임 분리를 해두어서, 다른 변경 없이 DelimiterExtractor 클래스 내 검증 조건만 추가할 수 있었다!

private boolean isNotCharacter(String delimiter) {
    return delimiter.length() != CHARACTER_LENGTH; // 1
}

 

2. 미션 제출!

기능 목록에 구현하면서 고민한 점, 다이어그램 등을 추가하며 보완을 마치고, 드디어 제출 완료!!

간단한 미션이었지만, 하나하나 다 뜯어보며 메타인지 열심히 해 본 한주였다 히ㅣ

 

느낀점

최선을 다해 리팩토링했지만, 여전히 찝찝한 부분이 있긴 하다(퍼사드 패턴이라던지,,책임 분리가 잘 되었는지 등).

어떤 부분을 더 고쳐야 할 지 스스로는 잘 모르겠기에,,,나머지는 코드리뷰를 통해 학습해보려 한다.

 

10/20 (월) Day 7

하루종일 소감문만 작성하였으니,,패스-!

 

느낀점

1주 차가 끝났다.

매일매일 기록 하는게 생각보다 쉽지 않다...
그래도 열심히 기록해둔 덕분에 내 사고 흐름이나 습관에 대해 알아볼 수 있었다.

또 학습한 것도 블로그에 자세히 기록하고 싶은데,,,

미션 구현하고, 구현을 위해 학습하고, 학습한 거 혼자 정리하고, 소감문 쓰고, 토론 참여하고 하면 시간이 어,,없다.
그래도 다음 주에는 시간 관리 잘 해서 한번 도전하는 걸로!

이제 열심히 코드 리뷰하며, 내가 놓친 부분들을 배워보도록 하겠다.

ㄲㅡㅅ!