외부활동/우아한테크코스 [프리코스]

[우아한테크코스 7기] 프리코스 1주차 회고

softmoca__ 2024. 10. 23. 15:54
목차

https://github.com/woowacourse-precourse/java-calculator-7/pull/654

 

[문자열 덧셈 계산기] 최영철 미션 제출합니다. by softmoca · Pull Request #654 · woowacourse-precourse/java-ca

1주차 미션을 작성하며 '작업한 내용'에 대한 회고 및 TIL 기록을 한 링크입니다 :) https://breezy-way-675.notion.site/10-15-1-TIL-120eba944b4380d289b6ec348159f5c5 ⛳️미션 기능 요구사항 목표 입력된 문자열에서

github.com

 

 

시작하며

7시간 같았던 프리코스 1주차 7일이 벌써 지나갔다 !

위 사진들은 우아한테크코스 지원서에 작성했던 목표를 이루는 과정 중 하나로서, 프리코스의 가장 중요한 존재 의미 자체가  '우아한테크코스'가 나와 맞는지 먼저 몸소 느껴보는것인 만큼 정규 교육 과정과 동일하게 주 5일, 하루에 8시간 이상을 온전히 프리코스 활동에 시간을 투자하며 몰입해보았다.

결론적으로 다양한 요구사항을 고려하며 시간 가는 줄도 모른채 계획한 시간 보다 더 많은 활동을 하며 여러방면의 다양한 고민과 학습을 통해 즐겁게 성장하는 나 자신을 발견하며 나의 성장 방향성과 너무 잘 맞는다고 느꼈다.

 

우선 1주차를 진행하며 '메타인지'를 통한 몰입 방향성의 중요성을 다시 한번 깨달으며 나 자신에 대해 이해하며 더 나은 성장을 할수 있는 발판을 찾게되었다.

 

 

 

 

고민했던 것 및 느낌점

1주차 미션의 기능 요구 사항은 간단하였다.

특정한 구분자를 가지는 문자열을 구분자로 분리한 후 숫자의 합을 반환하는것이다.

끝 없는 예외처리

하지만 미션 가이드에는 아래와 같은 두개의 문구가 있었고 이 두 문구로 인해 많은 고민을 하며 시간을 사용하였다.

"기능 요구 사항에 기재되지 않은 내용은 스스로 판단하여 구현한다."

"사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 애플리케이션은 종료되어야 한다."

 

우선 기능을 구현하기전 Readme.md에 구현할 기능 목록을 정리하는 과정에서  '사용자가 잘못된 값을 입력한 경우'를 고려하는 과정에서 너무 많은 경우의 수가 있었다.

- 빈문자열이 입력된 경우

- 음수가 입력된 겨우

- 올바른 형태로 입력하지 않은경우

- int, long, BigInteger을 넘는 숫자가 입력된경우

- Console.readline()으로 입력받은 STring의 문법적 최대 길이 

등등

 

하나하나의 예외를 기록하며 정리하며 예외처리에 끝이 없겠다라는 생각이 들었다.

그래서 우선 가이드 예시에 명시적으로 보이는 예외만 처리한채 모든 기능을 구현한 뒤 이후에 남은 시간에 모든 예외를 하나씩 처리하기로 하였다.

 

기능목록정리를 토대로 정상적인 작동에 대한 구현을 모두 마친 뒤 추가 예외를 처리하려고 하였다.

  private static int calculateSum(String input) {
        if (input.isEmpty()) {
            return 0;
        }
        input = input.replace("\\n", "\n");
        String delimiter = "[,:]";
        if (input.startsWith("//")) {
            String[] parts = input.split("\n", 2);
            delimiter = "[" + parts[0].substring(2) + "]";
            input = parts[1];
        }

위와 같은 흐름의 로직을 통해 입력값 하나하나에 대해 기본 구분자인지, 커스텀 구분자인지 확인하는 과정을 통해 예외를 처리하는 과정이 추가 될 수록 예외를 처리하기위 해서 추가된 코드로 인해 버그가 발생할 수 있는 위험성이 커짐을 느껴 프로그램 전체 로직 자체를 리팩토링 하였다.

나만의 예외처리 범위를 찾다.

하나하나 세부적인 경우를 나누어 예외를 처리하는것은 좋지 않은 방법임을 느껴 미션 가이드를 정독하며 다른 방법을 생각해보았다.

그리곤 가이드에 이미 주어진 대로 ' 기본 구분자 혹은 커스텀 구분자로 나누어지는 문자열 형태' 인지 아닌지를 처음 입력에서 검증을 하면 이후 세부적으로 예외를 검증하지 않아도 되겠다고 생각하였고 '정규표현식'을 활용하여 새롭게 프로그램을  구성하였다.

그 결과, 프로그램의 흐름이 한눈에 잡히며 버그가 발생할 위험성 또한 느껴지지 않게 되었다.

그럼에도 끝나지 않는 예외처리에 대한 고민

하지만 문법적 예외와 같은 더 많은 예외에 대해 고민을 하게 되었고, 추가적인 세부 예외처리를 해보았다.

그러다 역시나 '끝 없는 작업' 이라는 생각을 했고, 일단 최대한 남은 시간 떠오르는 예외를 잡아보고자 하였다.

예외 처리에 대한 고민 해결 

문득 우아한테크코스 선배님도 같은 고민을 하였는지, 어떻게 해결했는지 궁금하여 여러 우테코 활동 레포지토리와 코치님들의 리뷰를 보게 되었다.

코치님들과 크로원들간의 리뷰하는 과정을 보니 예외처리에 대한 내용보다는 더 좋은 코드에 대한 개선 사항과 근거에 대한 이야기가 대부분임을 알게 되었고 나의 잘못된 몰입방향성에 대해 깨달게 되었다 !

 

 

 

배운것 및 잘한점

1️⃣  메타인지를 통해 잘못된 몰입 방향성을 깨달다.

정보의 호수

프리코스 첫날인 오늘 카카오톡 오픈 채팅방과 프리코스 커뮤니티에 많은 이슈와 대화 주제가 나와 모두 하나하나 읽어보며 고민해보느라 시간을 많이 소비 하였다. 대부분이 많은 유익한 정보였지만 ‘미래의 먼 열매를 원하며, 정작 나의 밭에는 씨를 뿌리지 않고 있는 나’를 발견하였다. 즉, 이번에도 너무 많은 분석을 하고 미션을 임하려고 하는 나를 발견하였다.

그리곤 즉시 메타인지와 몰입의 방향성을 생각하며시 내가 본질적으로 해야 할 것에 집중하기로 하였고, 다른 사람과의 비교가 아닌 어제의 나, 저번 주차의 나의 성장에 집중하기로 하였다

 

 

 

2️⃣  Git의 기본 동작

https://velog.io/@lillynextdoor/Git%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC

 

1. Working Directory

  • 정의: 작업 중인 파일들이 저장되는 디렉토리(파일).
  • 역할:
    • 파일의 변경, 추가, 삭제가 자유롭게 이루어질 수 있음.
    • Git은 Working Directory의 변경 이력을 직접 추적하지 않음.
    • 변경된 파일은 Staging Area에 추가해야 커밋 준비가 가능.

2. Staging Area

  • 정의: Git에 커밋할 파일들이 올라가는 영역.
  • 역할:
    • 커밋할 변경 이력을 저장.
    • 커밋하지전, git add 명령어로 추가한 파일들이 임시로 저장되는 공간이다.
    • Stating Area에 추가된 파일들의 변경 이력이 추적이 된다.
    • Working Directory의 변경 이력을 직접 추적하지 않음.
    • 커밋 전에 변경된 파일들을 Staging Area에 추가하여 변경 이력을 정리 가능.

3. Local Repository

  • 정의: 로컬 Git 프로젝트의 메타데이터와 변경 이력이 저장되는 영역.
  • 역할:
    • 커밋된 변경 이력을 로컬 저장소에 저장.
    • 변경 이력은 브랜치(branch) 구조로 관리.
    • 브랜치를 변경하면 해당 브랜치의 커밋 히스토리를 확인 가능.

4. Remote Repository

  • 정의: GitHub 등 온라인 서비스 상에 있는 원격 저장소.
  • 역할:
    • 로컬 저장소의 변경 이력을 원격 저장소에 Push.
    • 원격 저장소의 변경 이력을 로컬 저장소로 Pull.
    • 다수의 사용자가 협업할 수 있는 환경 제공.

 

 

Fork와 Clone의 개념과 차이점

Fork란?

  • Fork는 다른 사람의 GitHub Repository를 내 GitHub 계정의 Repository로 복제하는 기능이다.
  • Fork된 저장소와 원본 저장소는 연결되어 있어, 원본 저장소에 새로운 커밋이 발생하면 내 Fork 저장소에도 이를 반영할 수 있으며 이 과정에서 fetch와 pull 명령어가 필요하다.
  • Fork한 Repository를 수정하고, 원본 Repository에 변경 사항을 적용하고 싶다면 Pull Request(PR)를 보내야 하며, PR이 승인되고 병합(Merge)되면 내가 수정한 내용이 원본 Repository에 반영된다.
  • PR 전까지는 Fork한 내 Repository에서만 변경 사항이 적용된다.

Clone이란?

  • Clone은 원격 Repository를 내 로컬 PC와 연결하여 데이터를 복사하는 작업이다.
  • Clone한 Repository는 로컬에서 작업할 수 있는 복사본을 제공한다.
  • 권한이 없는 경우 Clone한 프로젝트는 원본 Repository의 변경 사항을 로컬에서 Push할 수 없다.
  • 또한, Clone한 프로젝트는 원본 Repository의 로그에 접근할 수 없다.

Fork와 Clone의 주요 차이

기능 원본 Repository를 내 GitHub로 복제 원격 Repository를 로컬 PC로 복사
연결 대상 원본 Repository ↔ Fork된 Repository 로컬 PC ↔ 원격 Repository
권한 Fork 후 PR을 통해 원본 Repository에 반영 가능 권한이 없으면 원본 Repository에 Push 불가
변경 사항 적용 원본 Repository의 변경 사항을 반영 가능 (fetch 및 pull 필요) 원본 Repository의 로그 확인 불가

Fork: 원본 Repository를 내 GitHub 계정으로 복제하는 작업.

Clone: 원격 Repository를 내 로컬 PC로 복사하는 작업.

 

즉, Fork는 GitHub 계정 간 작업 연결을, Clone은 로컬과 원격 간 작업 연결을 지원한다.

 

 

커밋 컨벤션 정리

프리코스를 하기 이전 나는 git의 커밋을 그저 rollback을 하기 위한 도구로만 사용을 하였다.

하지만 프리코스릁 통해 AngularJS Git Commit Message Conventions에 대해 정리하며 '커밋'의 역할과 중요성에 대해 학습할수 있었다.

 

아래는 프리코스를 진행하며 사용할 커밋 컨벤션에 대해 정리한 내용이다.

커밋 메시지 헤더
<type>(<scope>): <summary>
  │       │             │
  │       │             └─⫸ 명령문,현재 시제사용, 대문자를 사용 X, 마침표로 끝내지 않는다.
  │       │
  │       └─⫸ Commit Scope: animations|benchpress|common|core|
  │
  └─⫸ Commit Type: feat|fix|refactor|docs|test
 <type> and <summary> fields are mandatory, the (<scope>) field is optional.

<type>에 들어갈 수 있는 항목들

  • feat : 새로운 기능 구현(요구사항 변경으로 기존 기능 추가, 수정, 삭제)
  • fix : 버그/오류 해결을 위한 코드 수정
  • refactor : 전면 수정, 코드 리팩토링
  • docs : README 등의 문서 수정, 주석 추가/수정
  • test: 테스트 관련 코드 추가/수정

<scope>에 들어갈 수 있는 항목들

  • 어디가 변경 되었는지(코드위치 등등)
  • scope는 생략이 가능하다.

<short summary> 요약 설명

  • 명령문, 현재 시제 사용
  • 대문자 사용 X, 마침표로 끝내지 않는다.

메시지 내용 (Message Body)

  • 제목 이후 한줄 띄우고 작성하기
  • 명령문, 현재 시제로 작성하길 권장한다.
  • 변경한 이유와 변경 전과의 차이점을 설명한다.

 

 

메시지 하단 (Message Footer)

→ 프리코스 중에는 지양하는 것이 오히려 좋다고 생각이 된다.

  • Footer는 이슈 해결 혹은 자동화 도구와의 연동을 위한 역할을 주로하며, 이슈 추적, 호환성 문제와 가튼 핵심 메타데이터를 담고 있어, 커밋 히스토리 관리와 자동화에 도움이 된다.
  • 하지만 프리코스에서는 나 혼자 진행을 하며, ‘이슈’를 거의 사용하지 않으며, 라이브러리 및 버전에 제한이 있어 호환성 관리도 진행하지 않는다.

Message Footer는 일반적으로 다음과 같은 경우에 작성된다:

  1. Breaking Changes: 기존 기능을 수정하거나, 새로운 요구사항으로 인해 기존 코드의 동작 방식이 변경될 때 작성된다. 이 경우, 이전 코드와 호환되지 않거나, 기존 기능이 제거되거나 변경될 수 있는 중요한 정보를 포함한다. 예를 들어, API가 변경되거나 함수의 동작 방식이 달라졌을 때, 다른 개발자들이 그 영향을 인지하고 필요한 변경을 할 수 있도록 안내하는 역할을 한다.
  2. 이슈 참조: 구현한 변경 사항이 특정 이슈나 버그를 해결하는 경우, 해당 이슈 번호를 참조하는 용도로 Message Footer를 사용한다. 이때 "Closes #123"처럼 이슈 번호를 명시하여, 해당 커밋이 어떤 문제를 해결하는지 명확하게 알 수 있다.

따라서, 새로운 기능을 추가할 때는 Message Footer를 반드시 작성할 필요는 없으며, 보통 기존 기능을 변경하거나, 호환성에 영향을 주는 중대한 수정이 있을 때 작성하는 것이 일반적이다.

  • 주요 변경 내역들은 다음과 함께 하단에 언급되어야 한다.
  • 변경점 (description of the change)
  • 변경 사유 (justification)

 

3️⃣ OpenJDK와 다양한 배포판들의 개념

OpenJDK는 Java Development Kit (JDK)의 오픈소스 구현이다.

오라클이 주도하여 개발되었으며, Java 표준의 오픈소스 버전으로, 누구나 자유롭게 사용할 수 있다. OpenJDK는 여러 회사들이 공동으로 유지하고 있으며, 다양한 배포판으로 제공된다.

JDK는 Java 애플리케이션을 개발하고 실행하는 데 필요한 도구 모음으로, 컴파일러, 런타임 환경 등을 포함한다.

 

OpenJDK를 기반으로 한 다양한 JDK 배포판이 존재하며, 각각의 배포판은 추가적인 최적화, 안정성, 보안 패치 등을 제공하거나 특정 벤더가 지원하는 기능을 포함할 수 있다.

주요 JDK 배포판은 다음과 같다:

  • Oracle JDK: 오라클에서 배포하는 상용 JDK로, OpenJDK 기반이지만 일부 상용 기능이 추가된다. 최신 업데이트 및 상업적 지원이 제공된다.
  • Amazon Corretto: 아마존에서 배포하는 OpenJDK 기반의 배포판으로, 장기적인 지원(LTS)을 제공하며, 안정성과 성능을 개선한 버전이다. AWS 환경에서 특히 사용된다.
  • Temurin (Eclipse Adoptium):
    • Eclipse 재단에서 관리하며 이전에는 AdoptOpenJDK로 불렸다.
    • 벤더 중립적이며, 다양한 플랫폼과 환경에서 안정적인 JDK를 제공하는 것을 목표로 한다.
    • TCK (Technology Compatibility Kit) 테스트를 통과해, Java 표준을 준수하며, Java SE 표준과의 호환성이 보장되고, 운영 환경과 로컬 개발 환경 모두에서 안정적으로 사용할 수 있다.

요약

  • OpenJDK는 Java의 공식 오픈소스 구현체이다.
  • Oracle JDK, Amazon Corretto, Eclipse Temurin 등은 모두 OpenJDK를 기반으로 만들어진 JDK 배포판이다. OpenJDK의 코드를 바탕으로, 각 벤더가 추가 기능이나 지원을 더해 자신들의 배포판을 제공한다.

 

JDK 여러 버전 깔고 사용하기

brew install --cask temurin11
brew install --cask temurin17
brew install --cask temurin21

vi ~/.zshrc

# (zshrc 파일에 아래 내용을 추가한 후 저장)
source ~/.zshrc

아래 내용 작성 후 저장
# 자바 버전 쉽게 변경하기 위한 alias 설정
alias java11='export JAVA_HOME=$JAVA_11_HOME'
alias java17='export JAVA_HOME=$JAVA_17_HOME'
alias java21='export JAVA_HOME=$JAVA_21_HOME'

# 현재 설정된 JAVA_HOME을 적용
export JAVA_HOME=$JAVA_21_HOME # 기본적으로 Java 21을 설정

 

source ~/.zshrc 명령어

현재 터미널 세션에 변경된 .zshrc 설정을 즉시 적용하기 위한 명령어이다.

  • ~/.zshrc 파일
    • 이 파일은 Zsh 셸의 환경 설정 파일이다
    • 사용자별로 정의된 환경 변수, alias(별칭), 경로 설정, 기타 설정들이 포함된다.
    • 이 파일은 Zsh 셸이 실행될 때마다 자동으로 실행되어 환경을 구성한다.
  • source 명령어
    • 지정된 파일의 내용을 현재 셸 세션에서 실행하도록 한다.
    • 파일에 정의된 명령어들이 현재 터미널 세션에 적용된다.
    • 즉, 셸을 다시 시작하지 않고도 변경된 설정을 즉시 적용할 수 있다.

역할

  • 파일을 적용하는 방법: .zshrc 파일을 편집하고 난 후 source ~/.zshrc 명령어를 실행하면, 해당 파일에 있는 새로운 설정이 현재 터미널 세션에 적용된다. 따라서, 셸을 재시작하지 않고도 설정이 반영된다.

→ 이제 간단한 명령어로 여러 JDK 버전을 넘나들며 사용가능 !

 

 

 

인텔리제이에서 21 사용 확인하기 하고 적용하기

1) fork한 레포 클론 받아서 인텔리제이로 가져오기

현재는 22 버전으로 사용중임을 확인

 

 

2) Gradle Build

 

3) Project SDK

 

 

4️⃣ 자바의 이스케이프 문자 처리 프로세스 이해 및 인텔리제이 디버깅 학습

String delimiter = "[,:]";
if (input.startsWith("//")) {
    String[] parts = input.split("\n", 2);  // "\n"을 기준으로 나눔
    System.out.println(parts.length);  // 디버깅용 출력
    for (String x : parts) {
        System.out.println(x);  // 디버깅용 출력
    }

    delimiter = "[" + parts[0].substring(2) + "]";  // 커스텀 구분자 추출
    input = parts[1];  // 구분자를 제외한 나머지 문자열
}

처음 미션을 구현하며 커스텀 구분자로 시작을 하는지 찾기 위한 로직을 위와 같이 작성하였다.

하지만 아래와 같이 예상치 못하게 이스케이프 문자를 인식하지 못하는 문제가 발생하였다.

이런저런 문자열을 조작하는 과정에서 디버깅을 하며 이런 저런 코드를 추가해보며 “//;\n1;2;3" 를 입력 했을 시 ‘인텔레제이 터미널 입력 후 콘솔에서 “\n”가 “\\n로 ” 변경된다고 가정 ‘ 을 하여 아래의 코드를 추가하니 원하는 로직이 수행되고 테스트코드가 SUCCESSFUL가 되었지만 해당 과정이 이해가 안되었다.

input = input.replace("\\n", "\n");// 입력에 \\n이 들어온 경우 실제 줄바꿈 문자로 변환

하지만 현재 내가 이해하고 있는 자바의 이스케이프 문자처리 지식으로는 이해가 되지 않았고 아래와같은 의문이 들어 인텔리제이 디버거에 대해 공부해 보았다.

  • 🤔 처음 인텔리제이에서 입력 받은 문자열의 “\n”가 어디서 어떻게 언제 처리가 되는것 인가 ?
  • 🤔  자바가 실행되는 과정중 문자열 “\n”가 어디서 어떻게 언제 처리가 되는 것인가 ?

인텔리제이 디버깅 학습

유튜브의 테코톡의 여러 영상들을 참고하여 실습을통해 아래와 같이 정리해보았다.

 

 

- 인텔리제이 버전마다 UI가 다르며 위치가 다르다. 하지만 대부분 비슷하게 생겼으니 직관적으로 확인할 수 있다.

- 주로 Step over와 resume 버튼을 많이 사용한다.

 

디버깅 UI 기능 요약

  • Resume : 다음 break point로 이동한다.
  • Step Over : 다음줄로 넘어간다. method call안으로 들어가지는 않는다.
  • Step Into : 지금 대기하고 있는 method call 내부로 들어간다.
  • Step Out : 실행을 시키고 나온다.(실행중인 스택(메서드)) 즉, 다음으로 넘어간다.
  • Drop Frame : Step Out과 똑같은데, 실행하지 않고 다음으로 넘어간다.
  • conditioned break point
    • ex) for문에서 디버깅이 번거롭다. → 50번쨰가 궁금한데 51번쨰로 넘어가도 뒤돌아갈 수 없다.→break 포인트가 잡힌 칸에있는 모든 메서드 사용 가능하다.
    • → break포인트 우클릭하면 condition 사용가능.
  • Evaluate Expresseion : 멈춘 지점에서 이런 저런 값을 계산해 볼 수 있다.
    • Evaluate 에서 실행한건 실제 코드에서 실행이된다. 즉, 반영된다.
  • Watch : Evaluate해보고 싶은걸 미리 지정할 수 있다.

 

디버깅을 활용하며 자바의 문자열처리 프로세스 이해

- 텍스트로 표현하기 애매한 단어는 최대한 사용을 지양하며 정리함. (ex) “실제 줄 바꿈 문자”, “문자 그대로의 \n” 등등

 

이스케이프 문자란 ?

  • 특정 문자를 특수한 의미로 해석하거나, 문자가 가진 원래의 의미를 변경하기 위해 사용되는 문법이다.
  • 이스케이프 문자는 일반적으로 백슬래시(\\)와 함께 사용된다.
  • 프로그래밍 언어나 문자열에서 특정 문자를 그대로 출력하거나, 다른 의미로 처리하고자 할 때 사용된다.
  • 이스케이프 문자는 특정 문자를 탈출(escape)시켜서 기본 의미를 벗어나도록 만들어 준다.

이스케이프 문자가 필요한 이유

  • 특수 문자 처리: 백슬래시(\\), 따옴표("), 작은따옴표(')와 같은 문자는 기본적으로 프로그래밍 언어에서 특정 역할을 한다. 문자열 내에서 이들을 문자 그대로 사용하려면 이스케이프 문자가 필요하다.
  • 제어 문자 사용: 줄 바꿈, 탭, 캐리지 리턴 등과 같은 제어 문자는 눈에 보이지 않지만 중요한 역할을 하므로 이스케이프 문자를 사용하여 처리한다.

이스케이프 문자와 정규 표현식

정규 표현식에서는 특수 문자를 문자 그대로 사용하고 싶을 때도 이스케이프 처리가 필요하다.

예를 들어, .(마침표)는 모든 문자를 의미하지만, 마침표를 문자 그대로 처리하려면 \\.와 같이 이스케이프 처리한다.

 

 

“//;\n1;2;3”가 입력값으로 들어오면 “\n”을 인식하지 못한다.

if (input.startsWith("//")) {
            String[] parts = input.split("\n", 2);

            delimiter = "[" + parts[0].substring(2) + "]";
            input = parts[1];
        }

 

→ “//;\n1;2;3”가 입력값으로 들어오면 “\n”을 인식하지 못한다.

 

 

input.replace("\\n", "\n");를 통해 “//;\n1;2;3”에서 문자열의 일부로서의 “\n”가 실제 문자 하나(줄바꿈 문자)로 변경

input = input.replace("\\n", "\n");

if (input.startsWith("//")) {
            String[] parts = input.split("\n", 2);

            delimiter = "[" + parts[0].substring(2) + "]";
            input = parts[1];
        }

 

→input.replace("\\n", "\n");를 통해 “//;\n1;2;3”에서 문자열의 일부로서의 “\n”가 실제 문자 하나(줄바꿈 문자)로 변경

→ input.split("\\n", 2);

를 통해 하나의 문자(줄바꿈 문자)를 구분자로 사용

 

\\\\n → \\\n→ \\n 즉, “\\n”가 백슬래시와 문자 n으로 인식되어 “//;\n1;2;3”내부의 “\n”을 찾아낸다.

if (input.startsWith("//")) {
            String[] parts = input.split("\\\\n", 2);

            delimiter = "[" + parts[0].substring(2) + "]";
            input = parts[1];
        }

 

\\\\n → \\\n→ \\n

즉, “\\n”가 백슬래시와 문자 n으로 인식되어 “//;\n1;2;3”내부의 “\n”을 찾아낸다.

 

5️⃣ 테스트코드 작성

추가적인 입력값과 그에 대한 예외 처리를 하며 매번 프로그램을 실행시키고 입력 값을 콘솔에 타이핑 하던게 너무 힘들었다. 그러던 와중 오후 3시게 되었고 다른 분들의 PR을 구경하며 ‘테스트 코드’를 작성하면 되겠다고 생각했었다.

아래와 같이 입력값에 따른 예상 결과와 원인을 정리한 후 이를 토대로 테스트코드를 작성하여 매번 프로그램을 실행시키지 않고도 수정한 코드로 인해 이전 로직들에 버그가 발생하지 않는지 확인할 수 있었고, 직접 타이핑을 치는것보다 훨씬 빠르게 동작을 확인할 수 있었다.

 

정상 결과 정상 입력

"”

1,2

1,2,3

1,2:3

//;\n1;2;3

 

정상 결과 특이한 입력

//;\n → 구분자만 있고 문자열이 없다→ 0반환

//;\n2;21; → 구분자로 끝나는 문자열

111 → 숫자만

//;\n1 → 숫자만

123,0021,213 → 문자열에 0이 있는 경우

//;\n → 커스텀 구분자는 정했지만 계산할 문자열이 없는 경우

 

예외 발생

//;\n2;21;-2 → 음수

1,,2 → 연속된 구분자

//;\n;;;→ 구분자만 있는경우

,,:: → 구분자만 있는 경우

1,2a3242,3 → 구분자 혹은 양수가 아닌 경우

//1\\n1;2;3 → 구분자로 사용할수 없는 숫자가 커스텀 구분자로 입력된 경우

9223372036854775807,1 → long 최대 범위 벗어난 경우

//;1;2;3 → "//"로 시작했지만, "\n"이 올바른 위치에 없을 경우

//\\n1,2,3 → //\n"처럼 구분자 없이 줄바꿈만 있는 경우

//ab\\n1ab2ab3 → 커스텀 구분자 길이가 2 이상인 경우

1,2,abc → 숫자가 아닌 값이 들어오는 경우

 

테스트 코드를 한번도 작성해 보지 않았던 나는, 늘 어깨 넘어로만 들었던 좋은 코드는 ‘테스트 코드’를 위함이다 라는 말로 인해 그만큼 어렵고 많은 공부가 필요하다고 생각했다.

하지만 현재 나의 애로사항에만 맞게, 수정한 코드가 다른 로직에 영향이 있는지 없는지 확인하는 용도 정도로만 케스트 코드를 작성해 보니 역시 해보지 않고 무작정 겁만 먹었다는 것을 느꼈으며 몸소 테스트 코드의 중요성과 편리성을 알게 되었다.

 

 

5️⃣ 인텔리제이 스타일 코드 설정

최종 제출에 앞서 가이드를 다시한번 정독하며 놓친게 없는지 확인해보았다.

코드 컨벤션을 잘 지켰는지 하나하나 확인하며 Command + Option + L (코드 포맷팅 단축키)를 사용하던 중 이전에 사용하던 Vscode의 Prettier가 생각나서 찾아보던 중 '우아한 테크코스 코드 포맷터' 파일을 발견하여 적용해보았다.

https://github.com/woowacourse/woowacourse-docs/blob/main/styleguide/java/intellij-java-wooteco-style.xml

 

1. IntelliJ 좌측 상단의 Settings  → Editer → Code Style → Java

2. Import Scheme → IntelliJ IDEA code style XML → WootecoStyle 적용

 

3. Settings  → Editer → Code Style 최종 확인

4. 코드를 저장할 때 마다 포매터 작동 시키기

 

Tools → Action on Save → Reformat code, Optimize imports 체크
→ 미사용 import 제거와 reformat code 기능을 저장 시마다 자동으로 동작 !

 

 

 

 

 

 

 

보완해야할 점 아쉬운점

1️⃣ 테스트코드

테스트코드를 그저 매번 프로그램을 실행시켜 콘솔에 입력하는 것이 번거로워 처음 테스트코드를 작성해보게 되었다.

해당 에로사항을 해결하는것에 큰 도움과 장점을 느끼긴했지만 너무 겉핥기식으로 배운 내용을 토대로 테스트코드를 작성한 점이 아쉬웠다. 이번 1주차를 통해 테스트 코드의 장점을 직접 느껴본 만큼 다음 주차부터는 테스트코드의 라이브러리를 하나씩 뜯어보고, '테스트주도개발시작하기'와 '자바와 Junit을 활용한 실용주의 단위 테스트'를 읽으며 더욱 깊은 이해를 토대로 잘 활용해보기 위해 노력해 보아야겠다.

 

2️⃣ MVC 패턴

최종 과제 제출 이후 ‘우아한테크코스 미션’ 관련 레포지토리를 구경하며 대부분의 크루원들이 비슷한 패키지 구조를 가지는 것을 확인 했다.

그리고 분명 우연이 아닌 모두 특정한 패턴을 적용한 것이라 생각 했고, 그 패턴이 MVC 패턴이라는것을 알게 되었다.

왜 그토록 많은 사람들이 해당 패턴을 사용했는지, 또한 나는 왜 그런 패턴에 대한 필요성을 느끼지 못하였는지 생각하며 우선 MVC 패턴이 무엇인지에 대해 정의와 적용 방법과 같은 큰 개념 흐름을 먼저 파악해 보았다.

 

짧은 2시간의 공부 끝에 아주 조금의 장점에 대한 느낌 이외엔 전혀 감이 오지 않았다.

1주차 미션을 구현하며 메서드가 많아 지고, 여러 로직이 하나의 파일에서 작성됨에 따라 점점 코드가 복잡해 지고 있으며, 그로 인해 예외처리가 힘들어 진다 라고 느꼈던 나는 ‘음.. 패키지와 파일을 분리하면 가독성이나 코드 구조 파악은 쉽겠는데.. 그게 끝인가 ?’ 라는 생각이 들었다. 제출 마감 시간 6시간 전 우선 역시 머리와 눈으로 이해한것과 실제 해보는 것에는 큰 차이가 있다는 것을 알고 있어 우선 얕은 지식으로라도 적용을 해보았다. 겉으로 보며 이론적으로만 느꼈던 장점들을 직접 몸소 느껴보니 확실히 가독성이 눈에 띄게 좋아짐을 느꼈고, 이후 추가 요구 사항에 생겨 코드를 수정할 일이 생겼을 때도 해당 작업이 어느 패키지에 있는지 빠르게 알수 있어 유지보수성도 높여줄꺼라고 생각했다.

 

하지만 너무 짧은 시간에 주요 핵심을 토대로 겉핥기식으로 공부한 뒤 적용을 해서 큰 아쉬움이 느껴졌다.

이러한 아쉬움을 토대로, 간단한 핵심을 통해 몸소 작성해보며 느낀 장점 뿐만 아니라 이후 2주차 미션 부터는 더욱 깊은 이해를 토대로 MVC 패턴을 적용하며 진행해 보고자 한다 !

 

✅ 코드 리뷰를 통한 개선 사항 Check 

1️⃣ Controller가 많은 역할을 하고있다.

안그래도 1주차 미션 회고를 통해 MVC 패턴에 대해 더욱 공부를하고 보완해야겠다 싶었는데 코드 리뷰를 통해 더욱 구체적인 개선 사항과 이를 통해 얻을수 있는 이점을 알게 되었다.

MVC 패턴을 공부하며 SRP라고 불리우는 단일책임원칙에 대해 더욱 공부해보며 이후 2주차에는 MVC 패턴을 더 잘 적용하며 SPR를 준수하도록 노력해보아야겠다.

 

2️⃣  중복된  로직

1주차 미션의 리뷰들에 가장 많은 내용으로 중복된 로직이 관한 이야기 였다 !

indent와  얼리 리턴에 대한 개념이 없었던 해당 개념에 대해 공부한 뒤  왜 다른 스터디 원들의 코드에 비해 나의 코드가 큰 덩어리 덩어리로 문맥을 가지고 있는지 알게 되었다.

이후 2주차에는 indent에 더 신경을 쓰며 가독성과 코드를 읽는 흐름에도 더욱 신경을써 봐야겠다.

3️⃣ 예외메세지를 Enum으로 관리 

1주차 나의 코드에서는 모든 예외에 관련된 문구가 Model 패키지 내부에 있어서 Enum의 필요성을 느끼지 못하였다. 하지만 스터디원들의 코드를 리뷰하며 다양한 예외를 처리하고 더욱 구체적이로 친절한 에러메세지를 제공해주는 것을 보고 Enum으로 에러메세지를 관리하는것에 대한 장점을 느끼게 되었다 ! 2주차에는 나도 Enum으로 에러메세지를 관리해보아야겠다 !