├── Week1 (21.11.24~30) ├── 1주차 미션 정리.md ├── 1주차 과제 회고.md ├── Test코드에 있는 NsTest & Assertion 분석.md ├── Unit Test 학습 내용 정리.md ├── Git 커밋 메세지 규약 정리 - The AngularJS commit conventions.md └── Google Java Style Guide.md ├── Week3 이후부터 최종 테스트 이전까지 ├── 최종 코딩테스트 대비 2.md └── 최종 코딩테스트 대비 1.md ├── README.md ├── Week2 (21.12.1~7) ├── Private메서드 테스트하기.md ├── MVC 패턴이란.md ├── 2주차 과제 정리.md └── 2주차 과제 회고.md ├── Week3 (21.12.8~14) ├── 일급 컬렉션(First Class Collection)이란.md ├── 싱글톤(Singleton) 패턴이란.md ├── 3주차 미션 정리.md ├── Enum 정복하기.md ├── 2주차 피드백 & 다른 지원자 코드 리뷰.md └── 3주차 미션 회고.md ├── 우테코 최종 코딩 테스트 후기.md └── 프리코스 참여 후기.md /Week1 (21.11.24~30)/1주차 미션 정리.md: -------------------------------------------------------------------------------- 1 | # 🚀 미션 간단 설명 2 | 해당 미션은 우리가 학생시절 자주 하였던 숫자 야구게임을 코드로 구현하는 미션입니다. 3 | 대결은 컴퓨터와 하는 것으로 컴퓨터가 랜덤하게 3자리 수를 만들고 유저는 해당 수를 맞추는 방식으로 진행됩니다. 4 | 5 | 컴퓨터가 만드는 값은 서로 서로 다른 1~9까지의 수로 이루어진 3자리 수의 숫자이며 입력값에 따른 힌트를 기반으로 숫자를 맞춰야합니다. 6 | 7 | ## 🔒 제약사항 8 | - 기능을 구현하기 전에 기능 목록을 만들고, 기능 단위로 커밋 하는 방식으로 진행해야한다. 9 | - 기능 요구사항, 프로그래밍 요구사항, 과제 진행 요구사항을 지켜야한다. 10 | - [Java code convention](https://naver.github.io/hackday-conventions-java)을 지키며 코딩해야한다. 11 | - indent depth가 3이 넘지 않도록 구현해야합니다. 12 | - Scanner, Random API대신 camp.nextstep.edu.missionutils에서 제공하는 Randoms, Console API를 활용해 구현해야 합니다. 13 | - Applicatoin Test에 주어진 테스트 케이스가 모두 통과해야합니다. 14 | 15 |
16 | 17 | # 🛠 구현할 기능 목록 18 | * Game 시작 메서드 생성 19 | * 랜덤 값으로 상대방(컴퓨터) 수 생성해주는 메서드 생성 20 | * 랜덤 값에 중복된 수가 포함되어 나오는지 체크 21 | * 사용자로부터 입력 받는 함수 생성 22 | * 입력 값이 잘못된 값인지 체크하는 함수 생성 (잘못된 값을 입력할 경우 **IllegalArgumentException**을 발생) 23 | * 서로다른 수인지 체크 함수 24 | * 1~9로만 이루어져 있는지 체크 함수 25 | * 3자리 수인지 체크 함수 26 | * 정답 여부 체크 함수 생성 27 | * 숫자가 일치하면 게임을 다시 시작할지 선택하는 함수를 호출 28 | * 정답과 다르다면 힌트 출력 29 | * 힌트 클래스 생성 30 | * 사용자 입력에 대한 힌트 탐색 함수 생성 31 | * 힌트 출력 함수 생성 32 | * 게임 restart를 할지 여부를 묻는 함수 호출 33 | 34 | 35 |
36 | 37 | # 📋 구현 체크 38 | * [ ] Game 시작 메서드 생성 39 | * [ ] 랜덤 값으로 상대방(컴퓨터) 수 생성해주는 메서드 생성 40 | * [ ] `camp.nextstep.edu.missionutils`에서 제공하는 Randoms API를 활용해 구현해야 한다. 41 | * [ ] Random 값 추출은 `camp.nextstep.edu.missionutils.Randoms`의 `pickNumberInRange()`를 활용해야한다. 42 | * [ ] 랜덤 값에 중복된 수가 포함되어 나오는지 체크 43 | * [ ] 사용자로부터 입력 받는 함수 생성 44 | * [ ] `camp.nextstep.edu.missionutils`에서 제공하는 Console API를 활용해야한다. 45 | * [ ] 입력 값은 `camp.nextstep.edu.missionutils.Console`의 `readLine()`을 활용해야한다. 46 | * [ ] 입력 값이 잘못된 값인지 체크하는 함수 생성 (잘못된 값을 입력할 경우 IllegalArgumentException을 발생) 47 | * [ ] 서로다른 수인지 체크 함수 48 | * [ ] 1~9로만 이루어져 있는지 체크 함수 49 | * [ ] 3자리 수인지 체크 함수 50 | * [ ] 정답 여부 체크 함수 생성 51 | * [ ] 숫자가 일치하면 게임을 다시 시작할지 선택하는 함수를 호출 52 | * [ ] 정답과 다르다면 힌트 출력 53 | * [ ] 힌트 클래스 생성 54 | * [ ] 사용자 입력에 대한 힌트 탐색 함수 생성 55 | * [ ] 힌트 출력 함수 생성 56 | * [ ] 게임 restart를 할지 여부를 묻는 함수 호출 57 | * [ ] 게임 restart여부에 대한 응답의 입력 값이 잘못된 값인지 체크 (잘못된 값을 입력할 경우 **IllegalArgumentException**을 발생) 58 | 59 |
60 | 61 | * [ ] indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현하였는가? 62 | * [ ] 3항 연산자를 사용하지 않고 구현하였는가? 63 | * [ ] 모든 테스트케이스가 성공하는가? 64 | 65 | 66 | -------------------------------------------------------------------------------- /Week3 이후부터 최종 테스트 이전까지/최종 코딩테스트 대비 2.md: -------------------------------------------------------------------------------- 1 | # 📝 D-1 2 | 오늘은 원래의 예정했던대로 프리코스기간에 마지막으로 하였던 과제를 다시 풀어봤습니다. 3 | 최종 코딩테스트가 하루 남은 만큼 오늘도 실제 시험에 응한다는 마인드로 **5시간안에 문제 풀이를 하자!!**는 목표를 세우며 문제 풀이를 하였습니다. 4 | 5 | 일단 결론부터 말씀드리면 오늘 문제를 처음부터 풀이만 하는데 소모한 시간은 **3시간 40분** 정도가 소모됐으며 시간이 남아 매직넘버를 포함한 메시지들을 상수로 바꾸는 등의 리펙토링 작업을 실시한 결과 **총 4시간** 정도의 시간이 소모되었습니다. 6 | 7 | 이번 문제 풀이를 할 때는 이미 알고 있는 문제이기도 하여 **구현 리스트**를 이전에 만들어뒀던 것을 가져다 사용했습니다. 구현할 리스트를 처음 작성하는데 넉넉잡아 30~40분 정도가 소모된다고 계산을 하여도 시간이 남는 것 같습니다. 8 | 9 | 물론 이번 문제는 이전에 처음부터 2번을 풀이하였던 문제이기도 하여서 빨리 풀 수 있었지만 그래도 이전에 풀었을 때보다 확실히 MVC를 적용함에도 불구하고 막히는 부분이 별로 없이 코드를 빠르게 작성할 수 있었던 것 같습니다. 10 | 11 | 오늘 작성한 코드의 구성은 어제 연습하였던 [subway-map-precourse](https://github.com/woowacourse/java-subway-map-precourse) 문제와 동일한 디렉토리 구조로 작성하였습니다. 12 | 13 | > 코드 구조에 관한 설명은 [최종 코딩테스트 대비-1](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-%EC%B5%9C%EC%A2%85-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%8C%80%EB%B9%84-1) 에서 `2. 더욱 체계가 갖춰진 MVC`파트를 통해 확인하실 수 있습니다. 14 | 15 | 오늘 작성한 코드는 확실히 자판기 미션을 처음 작성하였던 코드와 두번째로 작성한 코드보다는 훨씬 메서드와 클래스의 역할 구분이 잘 되어있는 것을 확인하실 수 있습니다. 덕분에 코드의 재사용과 중간중간 코드의 리펙터링이 필요할 때 쉽게 변경할 수 있던 것 같습니다. 16 | (바꿀 수만 있다면 오늘 작성한 코드를 3주차 미션 최종 제출 코드로 변경하고 싶네요😥) 17 | 18 | 오늘 코드를 작성하며 내일 제가 사용할 코딩 방식들을 몇가지 정리해보겠습니다. 19 | 20 | ## 1. 코드는 입력부분 부터 작성하자 21 | 말 그대로 입니다. 내일 있을 시험에서는 **코드는 입력 부분부터 프로그램 실행 결과 예시에 따라 순서대로 코딩을 진행할 예정입니다.** 22 | 23 | 과제를 진행할 때 저는 코드의 입력 부분의 작성을 하기 앞서 먼저 사용될 객체들과 예외상황 등을 먼저 작성하고는 하였습니다. 그 당시에는 과제 기간이 일주일이라는 넉넉한 시간이 주어져있어서 예외상황 처리와 같은 메서드 들은 test메서드를 작성하여 옳바르게 동작하는지 테스트를 먼저 할 수 있었습니다. 하지만 내일 있을 최종 테스트의 경우는 시간이 5시간으로 제한되어있기에 메서드 별로 테스트 코드를 작성하기에는 시간이 부족할 수 있기에 입력 부분부터 작성을 하며 내부 비즈니스 로직들로 뻗어갈 예정입니다. 24 | 25 | 그렇다면 각각의 로직별로 검증은 어떻게 하나?라고 생각하실 수 있습니다. 26 | 그래서 내일은 아래의 **디버깅 기능을 사용**하여 실행이 옳바르게 되는지 검증을 하려고 합니다. 27 | 28 | 29 | ## 2. 디버깅을 최대한 활용하자! 30 | ![](https://images.velog.io/images/seongwon97/post/4ad85937-0224-489f-b58f-187364c945f3/image.png) 31 | 32 | IntelliJ에서는 다음 사진과 같이 특정 코드 라인을 클릭하며 표시를 해주고 디버깅 모드로 실행을 시킨다면 앞서 체크해둔 라인에서 코드의 실행이 멈추게 됩니다. 33 | 34 | 해당 기능을 활용하면 각각의 변수에 할당된 값과 값의 변화를 쉽게 확인할 수 있습니다. 35 | 36 | 물론 프로그래밍을 할 때 Test코드의 작성과 디버깅을 모두 활용하면 좋으나 내일은 시간이 정해져있는 테스트인만큼 시간 단축을 하고자 Test코드 대신 디버깅모드를 활용하여 시험에 임해보겠습니다. 37 | 38 | 39 | # 마무리 40 | 내일 코딩테스트를 마지막으로 우테코의 선별과정은 끝이 납니다. 41 | 자기소개서 작성부터 지금까지 한달 반이 넘는 시간이 흘렀습니다. 지금까지 노력한 만큼 노력의 결실을 맺기 위해 내일도 최선을 다해서 시험에 임해보겠습니다. 42 | 43 | 44 | > 오늘 연습한 자판기 미션의 코드는 다음 링크를 통해 확인하실 수 있습니다. 45 | > https://github.com/Seongwon97/java-vendingmachine-precourse/tree/Prepare_final_test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # woowa_precourse_record 2 | 우아한테크코스의 프리코스를 진행하며 공부하고 배운 내용을 주차별로 정리한 공간입니다. 3 | 4 | 해당 공부 내용들은 아래의 블로그에도 업로드되었습니다. 5 | 6 | ### 👨🏻‍💻 작성한 과제 코드 7 | - [1주차 미션 - 숫자 야구 게임](https://github.com/Seongwon97/java-baseball-precourse) 8 | - [2주차 미션 - 자동차 경주 게임](https://github.com/Seongwon97/java-racingcar-precourse/tree/Seongwon97) 9 | - [3주차 미션 - 자판기](https://github.com/Seongwon97/java-vendingmachine-precourse/tree/Seongwon) 10 | - [최종 코딩테스트 미션 - 페어매칭관리 애플리케이션](https://github.com/Seongwon97/java-pairmatching-precourse/tree/Seongwon97) 11 | 12 | ### 📒 회고록 & 후기 13 | - [1주차 과제 회고](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-1%EC%A3%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C-%ED%9A%8C%EA%B3%A0) 14 | - [2주차 과제 회고](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-2%EC%A3%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C-%ED%9A%8C%EA%B3%A0) 15 | - [2주차 피드백 정리](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-2%EC%A3%BC%EC%B0%A8-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-%EB%A6%AC%EB%B7%B0-%EC%A0%95%EB%A6%AC) 16 | - [3주차 과제 회고](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-3%EC%A3%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C-%ED%9A%8C%EA%B3%A0) 17 | - [프리코스 참여 후기](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-%EC%B5%9C%EC%A2%85-%ED%9B%84%EA%B8%B0) 18 | - [최종 코딩테스트 대비-1](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-%EC%B5%9C%EC%A2%85-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%8C%80%EB%B9%84-1) 19 | - [최종 코딩테스트 대비-2](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%EC%B5%9C%EC%A2%85-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%8C%80%EB%B9%84-2) 20 | - [최종 코딩테스트 후기](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%EC%B5%9C%EC%A2%85-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%ED%9B%84%EA%B8%B0) 21 | 22 | ### 📕 공부하며 정리한 자료들 23 | - [Google Java Style Guide 번역](https://velog.io/@seongwon97/Google-Java-Style-Guide) 24 | - [Git 커밋 메세지 규약 정리 - The AngularJS commit conventions](https://velog.io/@seongwon97/Git-%EC%BB%A4%EB%B0%8B-%EB%A9%94%EC%84%B8%EC%A7%80-%EA%B7%9C%EC%95%BD-%EC%A0%95%EB%A6%AC-The-AngularJS-commit-conventions) 25 | - [Test코드에 있는 NsTest & Assertion 분석](https://github.com/Seongwon97/woowa_precourse_record/blob/main/Week1%20(21.11.24~30)/Test%EC%BD%94%EB%93%9C%EC%97%90%20%EC%9E%88%EB%8A%94%20NsTest%20%26%20Assertion%20%EB%B6%84%EC%84%9D.md) 26 | - [Unit Test란? (단위 테스트)](https://velog.io/@seongwon97/Unit-Test-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8) 27 | - [Private메서드의 Unit Test](https://velog.io/@seongwon97/Test-Private%EB%A9%94%EC%84%9C%EB%93%9C%EC%9D%98-Unit-Test) 28 | - [MVC 패턴이란?](https://velog.io/@seongwon97/MVC-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80) 29 | - [일급 컬렉션이란?](https://velog.io/@seongwon97/%EC%9D%BC%EA%B8%89-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%B4%EB%9E%80) 30 | - [자바의 Enum 정복하기](https://velog.io/@seongwon97/%EC%9E%90%EB%B0%94%EC%9D%98-Enum-%EC%A0%95%EB%B3%B5%ED%95%98%EA%B8%B0) 31 | - [싱글톤(Singleton) 패턴이란?](https://velog.io/@seongwon97/%EC%8B%B1%EA%B8%80%ED%86%A4Singleton-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80) 32 | -------------------------------------------------------------------------------- /Week2 (21.12.1~7)/Private메서드 테스트하기.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 지난주 우테코 프리코스 1주차 과정을 진행하며 Unit Test에 대한 전반적인 내용에 대해 학습하였습니다. 하지만 지난주 공부한 Java의 Unit test 내용으로는 Private 메서드에 대해서는 테스트를 하기 힘들어 Private 메서드를 테스트 하는 방법에 대해 공부해보고자 합니다. 3 | 4 | > 1주차에 공부한 Unit Test에 대한 자세한 내용은 [Unit Test (단위 테스트)](https://velog.io/@seongwon97/Unit-Test-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8)를 통해 확인해보실 수 있습니다. 5 | 6 | 7 | # Private Method의 Unit test 8 | Private 메서드는 기본적으로 외부 클래스에서의 접근이 불간으하여 해당 메서드를 Default메서드로 빼거나 Public메서드로 변경하지 않는 이상 테스트 클래스에서 접근이 불가능합니다. 하지만 테스트를 하기 위해 Private메서드를 Public으로 변경하는 행동을 하는 것은 차라리 테스트를 안하는게 더 낫다고 생각 될 정도로 잘못된 행동이라 생각됩니다. 9 | 10 | 일반적으로 Private메서드는 따로 개별적인 Test를 진행하지 않거나 Private메서드를 호출하는 Public메서드를 통해 테스트를 진행한다고 합니다. 하지만 프로그래밍을 하다보면 불가피하게 Private메서드를 테스트 해야할 상황이 분명히 존재할 것이기에 학습을 해보고자 합니다. 11 | 12 | Private Method를 테스트 하는 방법은 앞서 말한듯이 Public메서드를 통해 간접 테스트를 하는 방법이 있습니다. 그 외에는 Reflection을 이용하여 테스트하는 방법이 존재합니다. 13 | Reflection을 통한 private메서드 테스트 방법에 대해 알아보도록 하겠습니다. 14 | 15 | ## Private Method에 접근하기 (Reflection) 16 | ```java 17 | public class InputUtils { 18 | private static void checkCarNameLength(String carName) { 19 | if (carName.length() > MAX_CAR_NAME_LENGTH) { 20 | System.out.println(ERROR_CAR_NAME_LENGTH); 21 | throw new IllegalArgumentException(ERROR_CAR_NAME_LENGTH); 22 | } 23 | } 24 | } 25 | ``` 26 | 예시로 올린 checkCarNameLength()메서드는 carName이 MAX_CAR_NAME_LENGTH를 넘으면 exception을 발생시키는 **private메서드** 입니다. 다음 메서드를 테스트 해보는 코드를 작성하면 다음과 같습니다. 27 | 28 | **Test코드** 29 | ```java 30 | import org.junit.jupiter.api.DisplayName; 31 | import org.junit.jupiter.api.Test; 32 | 33 | import java.lang.reflect.InvocationTargetException; 34 | import java.lang.reflect.Method; 35 | 36 | import static constant.Constant.*; 37 | import static org.assertj.core.api.Assertions.assertThat; 38 | 39 | class InputUtilsTest { 40 | @DisplayName("[자동차 이름] 5자리 이상의 이름인 경우") 41 | @Test 42 | public void checkCarNameLengthTest() throws NoSuchMethodException { 43 | InputUtils inputUtils = new InputUtils(); 44 | Method method = inputUtils.getClass().getDeclaredMethod("checkCarNameLength", String.class); 45 | method.setAccessible(true); 46 | 47 | try { 48 | method.invoke(inputUtils, "christopher"); 49 | } catch (IllegalAccessException e) { 50 | e.printStackTrace(); 51 | } catch (InvocationTargetException e) { 52 | assertThat(e.getCause().getMessage()).isEqualTo(ERROR_CAR_NAME_LENGTH); 53 | } 54 | } 55 | } 56 | ``` 57 | **1. 먼저 Private 메서드를 가진 Class객체를 생성해줍니다.** 58 | ```java 59 | InputUtils inputUtils = new InputUtils(); 60 | ``` 61 | **2. 테스트하고자 하는 private메서드를 호출하는 Method클래스를 만들어줍니다.** 62 | ```java 63 | Method method = inputUtils.getClass().getDeclaredMethod("checkCarNameLength", String.class); 64 | ``` 65 | ※ 이때의 형식은 `(1에서 만든 클래스 객체).getClass().getDeclaredMethod.(테스트 할 메서드 명, 메서드에 들어갈 파라미터 타입)`과 같은 형태로 입력해줍니다. 66 | 67 | **3. Method객체에 담겨있는 private메서드가 접근이 가능하도록 만들어줍니다.** 68 | ```java 69 | method.setAccessible(true); 70 | ``` 71 | **4. `invoke`를 통해 메서드를 실행시켜줍니다.** 72 | ```java 73 | method.invoke(inputUtils, "christopher"); 74 | ``` 75 | ※ 형식은 `method.invoke(1에서 만든 클래스객체, 실제 넣을 파라미터 값)`의 형태로 입력해줍니다. 76 | 77 | > Exception확인 테스트를 할 때 지난주에 학습한 바와 같이 `final RuntimeException exception = assertThrows(RuntimeException.class, () -> inputUtil.getPlayerAnswer());`에서 exception의 메시지만을 비교하면 코드를 실행하며 `java.lang.reflect.InvocationTargetException`이 발생하였다며 테스트가 실패하는 것을 확인해 보실 수 있습니다. 78 | 이러한 결과가 나오는 이유는 private메서드를 테스트 하기 위해 사용한 리플렉션 API는 호출된 메서드의 예외를 `InvocationTargetException`로 묶기 때문입니다. 이를 해결하기 위해서는 try/catch를 사용하여 `InvocationTargetException`을 잡고 `getCause()`메서드를 사용하여 원래의 Exception내용을 확인해야합니다. 79 | 80 | 81 | 이와 같이 테스트를 진행하면 테스트가 옳바르게 진행되는 것을 확인할 수 있습니다. 82 | 83 | ![](https://images.velog.io/images/seongwon97/post/a432ab94-056d-4f17-99a5-b7700f94c054/image.png) 84 | 85 | # Reference 86 | - https://www.crocus.co.kr/1665 87 | - http://daplus.net/java-java-lang-reflect-invocationtargetexception%EC%9D%98-%EC%9B%90%EC%9D%B8%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C/ 88 | - https://til-perfectacle.netlify.app/2018/07/06/test-private-method-with-reflection/ -------------------------------------------------------------------------------- /Week2 (21.12.1~7)/MVC 패턴이란.md: -------------------------------------------------------------------------------- 1 | 우테코 프리패스 과정을 진행하며 보다 나은 코드와 코드의 구조를 만들고자 다른 지원자들의 코드 리뷰를 하며 제가 작성한 코드와 비교를 해봤습니다. 2 | 다른 지원자들의 제출 코드들을 보니 많은 지원자들이 MVC패턴을 적용하여 과제를 진행한 것을 확인할 수 있었습니다. 3 | MVC패턴은 이전에 스프링 프레임워크 학습을 하며 사용을 하였으나 스프링 프로젝트 외의 다른 프로젝트들에 적용을 할 생각을 하지 못하였습니다. 그래서 **이번 기회에 MVC패턴의 개념과 구조를 확실히 익히고 다음주 프리코스 과제부터 MVC패턴을 적용해보고자 합니다!!** 4 | 5 | # MVC 패턴이란? 6 | > 모델-뷰-컨트롤러(model–view–controller, MVC)는 소프트웨어 공학에서 사용되는 소프트웨어 디자인 패턴이다. 이 패턴을 성공적으로 사용하면, 사용자 인터페이스로부터 비즈니스 로직을 분리하여 애플리케이션의 시각적 요소나 그 이면에서 실행되는 비즈니스 로직을 서로 영향 없이 쉽게 고칠 수 있는 애플리케이션을 만들 수 있다. MVC에서 모델은 애플리케이션의 정보(데이터)를 나타내며, 뷰는 텍스트, 체크박스 항목 등과 같은 사용자 인터페이스 요소를 나타내고, 컨트롤러는 데이터와 비즈니스 로직 사이의 상호동작을 관리한다. 7 |
8 | 출처: [MVC - wikipedia](https://ko.wikipedia.org/wiki/%EB%AA%A8%EB%8D%B8-%EB%B7%B0-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC) 9 | 10 | ![](https://images.velog.io/images/seongwon97/post/3cbbbc86-20b1-4020-8517-e38d02c402e3/MVC.png) 11 | 12 | 여기서의 핵심은 MVC 패턴을 사용하면 사용자 인터페이스로부터 비즈니스 로직을 분리하여 비즈니스 로직을 쉽게 고칠 수 있는 애플리케이션이 된다는 것이라 생각됩니다. 13 | 14 | 그리고 과거에는 View에 모든 비즈니스 로직까지 넣어 코드의 길이가 길어지고 유지보수가 힘들었으나 최근에는 MVC모델은 코드를 3가지 형태로 나누어 개발을 하는 MVC가 기본적인 디자인패턴이 되어 사용되고 있다고 합니다. 15 | 16 | ## Model, View, Controller 17 | ### Model 18 | - Model은 **Data**와 애플리케이션이 **무엇**을 할 것인지를 정의하는 부분으로 **내부 비즈니스 로직을 처리하기 위한 역할**을 합니다. 19 | - 즉, 모델은 컨트롤러가 호출을 하면 DB와 연동하여 사용자의 입출력 데이터를 다루는 일과 같은 데이터와 연관된 비즈니스 로직을 처리하는 역할을 합니다. 20 | - 데이터 추출, 저장, 삭제, 업데이트 등의 역할을 수행합니다. 21 | 22 | Model은 다음과 같은 규칙을 갖고 있습니다. 23 | - 사용자가 편집하기를 원하는 모든 데이터를 가지고 있어야 합니다. 24 | - View나 Controller에 대헤서 어떤 정보도 알지 말아야 한다. 25 | - 변경이 일어나면, 변경 통지에 대한 처리방법을 구현해야만 한다. 26 | 27 | ### View 28 | - View는 사용자에게 보여주는 **화면(UI)**이 해당됩니다. 29 | - 사용자와 상호작용을 하며 컨트롤러로부터 받은 모델의 결과값을 사용자에게 화면으로 출력하는 일을 합니다. 30 | - MVC에서는 여러개의 View가 존재할 수 있습니다. 31 | - Model에서 받은 데이터는 별도로 저장하지 않습니다. 32 | 33 | View는 다음과 같은 규칙을 갖고 있습니다. 34 | - Model이 가지고 있는 정보를 따로 저장해서는 안됩니다. 35 | - Model이나 Controller와 같이 다른 구성요소들을 몰라야 합니다. 36 | - 변경이 일어나면 변경 통지에 대한 처리방법을 구현해야만 합니다. 37 | 38 | 📌 Model과 View는 서로의 존재를 몰라야 합니다. 39 | 40 | ### Controller 41 | - Controller는 **Model과 View 사이를 이어주는 인터페이스 역할**을 합니다. 42 | - 즉, **Model이 데이터를 어떻게 처리할지 알려주는 역할**을 합니다. 43 | - 사용자로부터 View에 요청이 있으면 Controller는 해당 업무를 수행하는 Model을 호출하고 Model이 업무를 모두 수행하면 다시 결과를 View에 전달하는 역할을 합니다. 44 | 45 | Controller는 다음과 같은 규칙을 갖고 있습니다. 46 | - Model이나 View에 대해서 알고 있어야 합니다. 47 | - Model이나 View의 변경을 모니터링 해야 합니다. 48 | 49 | ## MVC 구동 원리 50 | 51 | ![](https://images.velog.io/images/seongwon97/post/03739268-07e0-4f7f-aaa1-aeab2f739d61/%EA%B5%AC%EB%8F%99%EC%9B%90%EB%A6%AC.png) 52 | 53 | MVC패턴은 Spring프레임워크와 JSP를 사용하는 웹 애플리케이션 개발에 많이 사용되고 있습니다. 이 때의 웹 애플리케이션에서의 MVC의 구동 원리는 다음과 같습니다. 54 | 55 | 1. 웹 브라우저가 웹 서버에 웹 애플리케이션 실행을 요청한다. (MVC 구조가 WAS라고 보면 된다.) 56 | 2. 웹 서버는 들어온 요청을 처리할 수 있는 서블릿을 찾아서 요청을 전달한다. (Matching) 57 | 3. 서블릿은 모델 자바 객체의 메서드를 호출한다. 58 | 4. 데이터를 가공하여 값 객체를 생성하거나, JDBC를 사용하여 데이터베이스와의 인터랙션을 통해 값 객체를 생성한다. 59 | 5. 업무 수행을 마친 결과값을 컨트롤러에게 반환한다. 60 | 6. 컨트롤러는 모델로부터 받은 결과값을 View에게 전달한다. 61 | 7. JSP는 전달받은 값을 참조하여 출력할 결과 화면을 만들고 컨트롤러에게 전달한다. 62 | 8. 뷰로부터 받은 화면을 웹 서버에게 전달한다. 63 | 9. 웹 브라우저는 웹 서버로부터 요청한 결과값을 응답받으면 그 값을 화면에 출력한다. 64 | 65 | 출처: https://osy0907.tistory.com/63 66 | 67 | ## MVC의 장점 68 | - 기능별로 코드를 분리하여 하나의 파일에 코드가 모이는 것을 방지하여 가독성과 코드의 재사용이 증가한다. 69 | - 각 구성요소들을 독립시켜 협업을 할 때 맡은 부분의 개발에만 집중할 수 있어 개발의 효율성을 높여준다. <- 분업을 가능하게 해준다!!! 70 | - 개발 후에도 유지보수성과 확장성이 보장된다. 71 | 72 | ## MVC의 한계 73 | Model과 View는 서로의 정보를 갖고 있지 않는 독립적인 상태라고 하지만 Model과 View사이에는 Controller를 통해 소통을 이루기에 의존성이 완전히 분리될 수 없습니다. 그래서 복잡한 대규모 프로그램의 경우 다수의 View와 Model이 Controller를 통해 연결되기 때문에 컨트롤러가 불필요하게 커지는 현상이 발생하기도 합니다. 이러한 현상을 **Massive-View-Controller**현상이라고 하며 이를 보완하기 위해 MVP, MVVM, Flux, Redux등의 다양한 패턴들이 생겨났습니다. 74 | 75 | ![](https://images.velog.io/images/seongwon97/post/564e2e4f-9c18-4fce-8764-20ccff42cee4/image.png) 76 | 77 | # Reference 78 | - https://ko.wikipedia.org/wiki/%EB%AA%A8%EB%8D%B8-%EB%B7%B0-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC 79 | - https://medium.com/@jang.wangsu/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4-mvc-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80-1d74fac6e256 80 | - https://osy0907.tistory.com/63 81 | - https://junhyunny.github.io/information/design-pattern/mvc-pattern/ 82 | - https://tecoble.techcourse.co.kr/post/2021-04-26-mvc/ 83 | - https://ninetynine-2026.tistory.com/138 84 | - https://wooaoe.tistory.com/15 85 | - https://m.blog.naver.com/tlstjd436/222010976665 86 | - https://scshim.tistory.com/407 87 | -------------------------------------------------------------------------------- /Week2 (21.12.1~7)/2주차 과제 정리.md: -------------------------------------------------------------------------------- 1 | # 🚀 미션 간단 설명 2 | 해당 미션은 사용자가 입력한 자동차들이 N번의 시도로 Randoms메서드를 통해 나온 결과값에 따라 전진을 하며 3 | N번의 시도가 끝난 후 최종 우승자를 출력하는 프로그래밍 미션입니다. 4 | 5 |
6 | 7 | ## 🔒 제약사항 & 만들어야 할 필수 메서드 8 | ### 1. 자동차 9 | #### 1.1. 자동차가 갖는 조건 10 | 1. 주어진 객체 Code를 이용해야 한다. 11 | ```java 12 | public class Car { 13 | private final String name; 14 | private int position = 0; 15 | public Car(String name) { 16 | this.name = name; 17 | } 18 | // 추가 기능 구현 19 | } 20 | ``` 21 | 2. 전진하는 자동차 출력할 때 이름을 같이 출력해야 한다. 22 | 3. 이름은 5자 이하만 가능하다 23 | 4. 전진 조건 – 0~9사이에서 무작위 값을 구한 후 값이 4이상일 경우 전진한다. 24 | - 조건: (camp.nextstep.edu.missionutils.Randoms) 사용해야한다. 25 | 26 | #### 1.2. 자동차가 갖는 메서드 27 | 1. 전진(해당 메서드에서 Position위치 변경) 28 | 2. 전진을 할지 여부 판단하는 메서드(Random값을 구하였을 때 4이상인지만 판별) 29 | 30 | ### 2. 입력 31 | #### 2.1. 입력 조건 32 | 1. 자동차 이름은 쉼표(,)를 기준으로 구분 33 | 2. 이름은 5자 이하만 가능. 34 | 3. 사용자는 몇번의 이동을 할 것인지 입력할 수 있어야 한다. 35 | 4. 잘못된 입력 값이 있을 경우 IllegalArgunentException을 발생시키고 "[ERROR]"로 시작하는 에러 메시지 출력 후 재입력을 받는다. 36 | 37 | #### 2.2. 입력 부분에서 만들 메서드 38 | - 경주할 자동차 이름 입력 받는 메서드 39 | - 시도할 회수를 입력 받는 메서드 40 | - 잘못된 입력 값을 판단하는 메서드 41 | - 자동차 이름이 5초과인 것을 판별 42 | - 시도할 회수가 숫자가 아닌 경우를 판별 43 | 44 | ### 3. 출력 45 | #### 3.1. 출력 조건 46 | - 완료 후 우승자를 출력해야 한다. 47 | - 우승자는 1명 이상일 수 있으며 여러명일 경우 쉼표를 이용하여 구분한다.) 48 | - 각 차수별로 결과를 출력해야한다. (5회 실행이면 5번 결과 출력) 49 | 50 | #### 3.2. 출력 부분에 만들 메서드 51 | - 차수별 출력 메서드 52 | - 최종 우승자 출력 메서드 53 | 54 | 55 | ### 4. 프로그래밍 요구사항 56 | - JDK 8 버전 사용 57 | - Indent를 2까지만 허용 58 | - 3항 연산자 사용 금지 59 | - 메서드는 최대한 한가지 기능만! 60 | - 메서드의 길이가 15라인을 넘지 않도록 구현 61 | - Else 사용 금지! -> if절에서 return 하는 방식으로 구현하도록! 62 | - Random, Scanner API대신 camp.nextstep.edu.missionutils에서 제공하는 Randoms, Console API를 활용! 63 | - 과제에 제안된 Car객체를 사용해야한다. 64 | - 객체의 기본 생성자 추가 금지 65 | - name, position의 접근 제어자인 private 변경 금지! 66 | - 가능하다면 setPosition메서드 추가하지 않고 구현하도록! 67 | 68 |
69 | 70 | # 🛠 구현할 기능 목록 71 | - Game 시작 메서드 생성 72 | - 사용자 입력관련 메서드 구현 73 | - 경주할 자동차 이름 입력 받는 메서드 구현 74 | - 여러 자동차의 이름 구분은 쉽표로 구분 75 | - 시도할 회수를 입력 받는 메서드 구현 76 | - 잘못된 입력 값을 판단하는 메서드 구현 77 | - 자동차 이름 입력이 잘못된 타입으로 들어오는 경우 78 | - ex1) "mike,james,christopher" <- 자동차 이름이 5초과인 것이 존재 79 | - ex2) "mike,james," <- 문장 끝이 쉽표로 끝난다. 80 | - ex3) "mike,,james" <- 쉽표가 2개 붙어서 존재 81 | - ex4) "mike, james" <- 쉽표 옆에 공백이 존재 82 | - ex5) ",mike,james" <- 문장 시작이 쉽표로 시작하는 경우 83 | - ex6) "" <- 입력이 없는 경우 84 | - ex7) "mike,mike" <- 중복된 이름이 입력되는 경우 85 | - 시도할 회수의 입력이 잘못된 경우 86 | - 시도할 회수가 숫자가 아닌 경우를 판별 87 | - 입력값이 없는 경우 88 | - 전진 조건에 따라 전진하는 메서드 구현 89 | - Random메서드를 사용해 전진 여부를 판단하는 메서드 구현 90 | - Positoin값을 올려주는 전진 메서드 구현 91 | - 결과 출력 메서드 구현 92 | - 차수별 출력하는 메서드 구현 93 | - 최종 우승자를 출력하는 메서드 구현 94 | 95 | 96 |
97 | 98 | # 📋 구현 체크 리스트 99 | * [X] Game 시작 메서드 생성 100 | * [X] 사용자 입력관련 메서드 구현 101 | * [X] 경주할 자동차 이름 입력 받는 메서드 구현 102 | * [X] 여러 자동차의 이름 구분은 쉽표로 구분 103 | * [X] 잘못된 값을 입력할 경우 **IllegalArgumentException**을 발생시켰는가? 104 | * [X] 잘못된 값에 대해 "[ERROR]"를 통한 메시지를 출력 후 입력을 다시 받았는가? 105 | * [X] 시도할 회수를 입력 받는 메서드 구현 106 | * [X] 잘못된 값을 입력할 경우 **IllegalArgumentException**을 발생시켰는가? 107 | * [X] 잘못된 값에 대해 "[ERROR]"를 통한 메시지를 출력 후 입력을 다시 받았는가? 108 | * [X] 잘못된 입력 값을 판단하는 메서드 구현 109 | * [X] 자동차 이름이 5초과인 것을 판별하였는가? 110 | * [X] 시도할 회수가 숫자가 아닌 경우를 판별하였는가? 111 | * [X] 입력 값은 `camp.nextstep.edu.missionutils.Console`의 `readLine()`을 활용하였는가? 112 | * [X] 전진 조건에 따라 전진하는 메서드 구현 113 | * [X] Random메서드를 사용해 전진 여부를 판단하는 메서드 구현 114 | * [X] Random 값 추출은 `camp.nextstep.edu.missionutils.Randoms`의 `pickNumberInRange()`를 활용하였는가? 115 | * [X] 결과 출력 메서드 구현 116 | * [X] 차수별 출력하는 메서드 구현 117 | * [X] 최종 우승자를 출력하는 메서드 구현 118 | 119 |
120 | 121 | * [X] JDK 8 버전을 사용하였는가? 122 | * [X] indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현하였는가? 123 | * [X] 3항 연산자를 사용하지 않고 구현하였는가? 124 | * [X] 모든 테스트케이스가 성공하는가? 125 | * [X] 모든 메서드의 길이가 15라인을 넘지 않았는가? 126 | * [X] Else를 사용하지 않았는가? 127 | * [X] Car객체에서 기본 생성자를 추가하지 않았는가? 128 | * [X] Car객체에서 name, position 접근자를 private에서 변경하지 않았는가? 129 | * [X] Car객체에서 setPosition()메서드를 추가하지 않고 구현하였는가? 130 | * [X] 클래스 분리하는데 노력을 하였는가? 131 | 132 |
133 | 134 | **1주차 피드백 반영** 135 | * [X] 변수, 메서드, 클래스의 이름이 의도를 드러내며 축약하지 않게 작성하였는가? 136 | * [X] 컨벤션을 모두 지켰는가? 지키지 않았으면 IDE의 코드 정렬기능을 활용하여라 137 | * [X] 의미 없는 주석을 달지 않았는가? 138 | * [X] 코드의 중복이 없도록 구현하였는가? 139 | * [X] 커밋 메시지를 옳바르고 이해가능하게 작성하였는가? 140 | * [X] 매직넘버 대신 상수(`static final`)로 코드의 가독성을 높였는가? 141 | * [X] 클래스를 상수, 멤버 변수, 생성자, 메서드 순으로 작성하며 구현 순서를 지켰는가? 142 | * [X] README.md파일을 살아있는 문서를 만들기 위해 노력하였는가? 143 | 144 | -------------------------------------------------------------------------------- /Week3 (21.12.8~14)/일급 컬렉션(First Class Collection)이란.md: -------------------------------------------------------------------------------- 1 | # 일급 컬렉션(First Class Collection)이란? 2 | 일급 컬렉션을 간단하게 설명하면 **Collection**을 **Wrapping**하면서 **그 외의 다른 멤버 변수가 없는 상태**를 일급 컬렉션이라고 합니다. 3 | 4 | 예시를 들면 다음과 같습니다. 5 | 6 | ```java 7 | List carList = new ArrayList<>(); 8 | 9 | for (String carName : carArr) { 10 | carList.add(new Car(carName)); 11 | } 12 | ``` 13 | 다음과 같은 collection을 아래와 같이 **wrapping**하는 것이 일급 컬렉션입니다. 14 | ```java 15 | public class Cars { 16 | // 멤버 변수가 하나밖에 없다는게 중요!! 17 | private List carList; 18 | 19 | public Cars(List carList) { 20 | this.carList = carList; 21 | } 22 | } 23 | ``` 24 | 25 | > 일급 컬렉션은 **소트윅스 앤솔로지**의 [객체지향 생활체조 파트의 규칙 8](https://developerfarm.wordpress.com/2012/02/01/object_calisthenics_/) 에서 언급이 되었다고 합니다. 26 | >> **규칙 8: 일급 콜렉션 사용** 27 | 이 규칙의 적용은 간단하다. 28 | 콜렉션을 포함한 클래스는 반드시 다른 멤버 변수가 없어야 한다. 29 | 각 콜렉션은 그 자체로 포장돼 있으므로 이제 콜렉션과 관련된 동작은 근거지가 마련된셈이다. 30 | 필터가 이 새 클래스의 일부가 됨을 알 수 있다. 31 | 필터는 또한 스스로 함수 객체가 될 수 있다. 32 | 또한 새 클래스는 두 그룹을 같이 묶는다든가 그룹의 각 원소에 규칙을 적용하는 등의 동작을 처리할 수 있다. 33 | 이는 인스턴스 변수에 대한 규칙의 확실한 확장이지만 그 자체를 위해서도 중요하다. 34 | 콜렉션은 실로 매우 유용한 원시 타입이다. 35 | 많은 동작이 있지만 후임 프로그래머나 유지보수 담당자에 의미적 의도나 단초는 거의 없다. 36 | 37 | # 일급 컬렉션을 왜 사용할까? 38 | 일급 컬렉션을 사용하면서 얻는 이점은 다음과 같습니다. 39 | 1. 비지니스에 종속적인 자료구조 40 | 2. Collection의 불변성을 보장 41 | 3. 상태와 행위를 한 곳에서 관리 42 | 4. 이름이 있는 컬렉션 43 | 44 | ### 1. 비지니스에 종속적인 자료구조 45 | 우테코 프리코스 2주차 과제의 자동차의 객체를 예시로 들면 `중복된 이름이 있으면 안된다.`, `이름은 5자리 이하의 영어 이름이어야 한다.`와 같은 조건이 있습니다. 46 | 47 | 해당 조건들을 서비스 메서드에서 구현을 한다면 자동차 객체리스트가 들어간 모든 장소에서 해당 자동차 리스트에 대한 검증 코드가 들어가야 하는 문제점이 발생합니다. 48 | 49 | 이러한 문제는 아래의 코드와 같이 **일급 컬렉션을 만들어 특정 조건으로 만들 수 있는 새로운 자료구조를 생성**하면 해결할 수 있습니다. 50 | 51 | ```java 52 | public class Cars { 53 | // 멤버 변수가 하나밖에 없다는게 중요!! 54 | private List carList; 55 | 56 | public Cars(List carList) { 57 | validateCarName(carList); 58 | validateDuplicateName(carList); 59 | this.carList = carList; 60 | } 61 | 62 | ... 63 | 64 | } 65 | ``` 66 | 67 | ### 2. Collection의 불변성을 보장 68 | Java의 final은 불변을 만들어주는 것이 아니라 재할당만을 금지합니다. 그리하여 `final List carList;`와 같이 만들어도 carList은 재할당만 불가능 할 뿐이지 `add`, `remove`와 같은 메서드로 내용을 변경할 수는 있습니다. 69 | 70 | Java에서 final로 만들 수 없는 **불변 객체는 일급 컬렉션과 래퍼 클래스의 방법으로 해결해야합니다.** 71 | 72 | ```java 73 | public class Cars { 74 | // 멤버 변수가 하나밖에 없다는게 중요!! 75 | private List carList; 76 | 77 | public Cars(List carList) { 78 | this.carList = carList; 79 | } 80 | 81 | public int getCarListSize() { 82 | return carList.size(); 83 | } 84 | } 85 | ``` 86 | 일급 컬렉션을 만든 위의 코드를 보면 carList는 생성된 이후 `getter`, `setter`가 따로 없어 내부 값의 변경이 불가능 한 것을 확인할 수 있습니다. 87 | 88 | > ※ 우테코 2기의 티거님의 [일급 컬렉션을 사용하는 이유](https://tecoble.techcourse.co.kr/post/2020-05-08-First-Class-Collection/) 의 정리 글을 보니 불변성을 보장하는 일급 컬렉션을 만들려면 `getter`, `setter`가 없는 클래스를 생성하거나 생성자를 만들 때 `unmodifiableList`를 사용하여 `return Collections.unmodifiableList(carList);`와 같은 코드를 작성해야하는 것을 확인했습니다. 89 | 즉, **일급 컬렉션을 만들 때는 컬렉션 값을 그대로 반환하는 기능은 두지 않고 가공된 값을 반환하거나 `unmodifiableList`를 사용하여 불변을 보장해야한다!** 90 | 91 | ### 3. 상태와 행위를 한 곳에서 관리 92 | 일급 컬렉션은 값과 로직이 함께 존재하여 외부에서의 **중복된 메서드의 생성**과 같은 문제를 해결해줍니다. 93 | 94 | 예를 들어 1,2,3,4학년의 정보를 하나의 List로 관리하고 각 학년의 평균 수강 학점을 구하려 한다면 각 학년 정보별로 중복된 여러 메서드를 생성할 수 있을 것입니다. 95 | 96 | 그러면 코드의 길이가 길어지고 중복 코드가 발생하며 가독성 또한 떨어지게 될 것입니다. 97 | 98 | 이러한 문제는 일급 컬렉션을 생성하고 해당 메서드들을 일급 컬렉션 내에 만들어두고 외부에서는 호출을 하여 사용하도록 프로그래밍하면 **상태와 행위를 한 곳에서 관리**할 수 있습니다. 99 | 100 | ### 4. 이름이 있는 컬렉션 101 | 대학교 1,2,3,4학년의 정보를 List로 관리한다면 102 | ```java 103 | List freshman = new ArrayList<>(); 104 | List sophomore = new ArrayList<>(); 105 | List junior = new ArrayList<>(); 106 | List senior = new ArrayList<>(); 107 | ``` 108 | 와 같이 만들 수 있습니다. 하지만 해당 코드는 개인이 프로젝트를 진행하였을 때는 문제가 없으나 거대한 팀 단위의 개발을 하게 된다면 다음과 같은 문제가 발생할 수 있습니다. 109 | 1. 해당 객체들을 검색을 할 때 변수명으로만 검색을 할 수 있어 변수명을 모를 시 검색을 하기 어렵다 110 | 2.단순히 변수명에 불과하여 의미 부여가 어렵다. 111 | 112 | 이러한 문제는 각각의 학년을 일급 컬렉션으로 만들어 관리를 한다면 해당 컬렉션을 기반으로 검색을 하면 되기에 해결할 수 있습니다. 113 | 114 | ```java 115 | Freshman freshman = new Freshman(~~); 116 | Sophomore sophomore = new Sophomore(~~); 117 | Junior junior = new Junior(~~); 118 | Senior senior = new Senior(~~); 119 | ``` 120 | 121 |
122 | 123 | ※ 해당 내용은 [일급 컬렉션 (First Class Collection)의 소개와 써야할 이유](https://jojoldu.tistory.com/412) 를 기반으로 작성하였습니다. 124 | 125 | 126 | # Reference 127 | - https://jojoldu.tistory.com/412 128 | - https://tecoble.techcourse.co.kr/post/2020-05-08-First-Class-Collection/ 129 | - https://brainbackdoor.tistory.com/140 130 | -------------------------------------------------------------------------------- /우테코 최종 코딩 테스트 후기.md: -------------------------------------------------------------------------------- 1 | 오늘 드디어 우아한테크코스 4기의 선별과정의 마지막 과정인 최종 코딩테스트를 봤습니다. 2 | 3 | 최종 코딩테스트의 문제는 작년 3기의 선별과정의 최종 미션이 3주차 미션과 비슷한 내용이어서 올해도 마지막 3주차 과제였던 [자판기 미션](https://github.com/woowacourse/java-vendingmachine-precourse) 과 비슷한 내용의 미션일거라 예상을 하였습니다. 하지만 저의 예상과는 다르게 3주차 미션과 완전히 다른 미션이 나왔습니다. 4 | 5 | 올해 우테코 4기의 최종 미션은 아래의 링크를 통해 확인해보실 수 있습니다. 6 | > **우테코 4기 최종 미션 - 페어매칭관리 애플리케이션** 7 | > https://github.com/woowacourse/java-pairmatching-precourse 8 | 9 | # 🎯 미션 수행 내용 10 | 이번 미션은 우테코 페어 프로그래밍의 팀 매칭을 프로그래밍하는 미션이었습니다. 11 | 미션의 기능은 크게 **페어 매칭 기능**, **페어 매칭 조회 기능**, **페어 매칭 초기화 기능**이 있습니다. 12 | 기능들 중의 메인 기능은 페어 매칭 기능었으며 해당 기능에서는 입력 값의 유효성 검사, 재매칭 여부, 페어 생성 등의 여러 세부 기능들로 나뉘었습니다. 그리고 프리코스 기간에는 사용하지 않았던 파일 입출력을 통해 크루의 정보를 읽어와야하는 조건 또한 있었습니다. 13 | 14 | 개인적으로는 지난 3주차 미션보다는 어려웠다고 생각됩니다. 15 | 16 | > **제가 최종 미션으로 제출한 코드는 다음 링크를 통해 확인하실 수 있습니다.** 17 | > https://github.com/Seongwon97/java-pairmatching-precourse/tree/Seongwon97 18 | 19 | # 👊🏻 신경쓴 점과 아쉬운 점 20 | ## Todo List 작성 21 | 프리코스 과정동안에는 Todo List를 `README.md`파일의 내용을 삭제하고 진행하였습니다. 그 당시에는 미션을 1주일이라는 기간동안 진행하여 내가 README파일에 새로 작성한 Todo List와 main branch에 있는 초기 README파일을 번갈아보며 미션을 진행하여도 크게 불편하다는 생각은 하지 못하였습니다. 하지만 프리코스 과정이 끝나고 최종 코딩테스트 준비를 하며 시간 제한을 두고 여러 문제를 보니 내가 작성한 Todo list외에도 기존 README파일에 작성되어있는 코드를 실행하였을 때의 출력문 등을 보기 위하여 웹으로 main branch를 접근하여 README파일을 보는 것은 매우 비효율적이라 생각되었습니다. 그래서 이번 최종 미션을 진행하였을 때는 `ToDoList.md` 파일을 새로 생성하여 해당 파일에 내가 이해한 미션의 정보와 Todo list를 작성하였습니다. 22 | 23 | ![](https://images.velog.io/images/seongwon97/post/572aa7d7-5fc8-49e5-9ab4-a496bd8d4b81/image.png) 24 | 25 | ToDoList.md파일과 기존의 README.md파일과 함께 하나의 창으로 화면을 분할하여 기능 구현들을 하다보니 확실히 구현해야할 내용 및 출력 결과 등을 한번에 볼 수 있던 것 같습니다. 26 | 27 | 한 개의 기능 구현이 끝나고 다음 기능 구현으로 넘어갈 때 TodoList를 통해 어떤 기능을 다음에 구현해야하는지 체크하고 README에서 출력 형태를 보다보니 다음 구현할 기능의 이해를 빠르게 할 수 있었던 것 같습니다. 28 | 29 | ## Enum 적극 활용 30 | 이번 미션을 진행하며 코스, 미션레벨, 미션의 종류와 같은 데이터들은 모두 Enum으로 관리하도록 프로그래밍하였습니다. (각각 Course, Level, Mission이라는 enum을 생성하여 사용하였습니다.) 해당 데이터들을 enum으로 관리를 하니 코드의 가독성이 높아졌으며 각각 `isExist()`메서드를 구현하여 사용자로부터 과정, 레벨, 미션의 입력값을 받았을 때 해당 값이 실제 존재하는 값인지 쉽게 판단할 수 도 있던 것 같습니다. 31 | 32 | enum을 사용한 코드의 예시는 다음과 같습니다. 33 | ```java 34 | public enum Course { 35 | BACKEND("백엔드"), 36 | FRONTEND("프론트엔드"); 37 | 38 | private String name; 39 | 40 | Course(String name) { 41 | this.name = name; 42 | } 43 | 44 | public String getName() { 45 | return name; 46 | } 47 | 48 | public static List getList() { 49 | return Arrays.stream(Course.values()) 50 | .map(Course::getName) 51 | .sequential() 52 | .collect(Collectors.toList()); 53 | } 54 | 55 | public static boolean isExist(String name) { 56 | List result = Arrays.stream(Course.values()) 57 | .filter(course -> course.getName().equals(name)) 58 | .collect(Collectors.toList()); 59 | if (result.size() == 1) { 60 | return true; 61 | } 62 | return false; 63 | } 64 | 65 | public static Course getEnumCourse(String name) { 66 | return Arrays.stream(Course.values()) 67 | .filter(course -> course.getName().equals(name)) 68 | .collect(Collectors.toList()).get(0); 69 | } 70 | } 71 | ``` 72 | 73 | ## 디버깅의 활용 74 | 시험 보기 하루 전날 프리코스 3주차 미션인 자판기 미션을 다시 구현해보고 정리한 포스트인 [최종 코딩테스트 대비-2](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%EC%B5%9C%EC%A2%85-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%8C%80%EB%B9%84-2) 에서 말한 바와 같이 이번 테스트에서는 테스트코드 대신 디버깅을 사용하여 데이터가 옳바르게 넘어가고 저장되었는지를 체크하였습니다. 75 | 76 | 디버깅 기능을 사용하다보니 어떠한 부분에서 데이터의 누락이 발생하였고 오류가 발생하게 되었는지도 확실히 체크할 수 있어 오류 해결에 많은 도움이 되었던 것 같습니다. 77 | 78 | 79 | ## 시간 부족의 아쉬움 80 | 최종 코딩테스트를 진행하며 가장 걱정했던 것이 시간문제였습니다..시험 직전인 목, 금에도 우테코 3기의 3주차 프리코스 미션과 올해 3주차 프리코스 미션을 시간 제한을 두고 문제를 풀이해보며 개발 속도가 빨라지긴 했으나 그래도 시간 부족 문제를 가장 고민하였습니다.. 81 | 82 | 이번 미션을 진행하면서 큰 기능들은 모두 구현하였으나 페어 매칭 기능에서 **"이전에 매칭된 사람과는 매칭되지 않도록 구현"**하는 내용을 구현하지 못하였습니다. 83 | 84 | 5시간이라는 시간동안 막힘없이 코딩을 하였다면 충분히 모든 기능들을 구현할 수 있었으나 중간중간 `stream`과 출력 부분의 데이터 출력에 막히는 부분이 있어 해당 파트의 시간 소모가 너무 많았던 것 같습니다. 85 | 86 | 30분 정도의 시간이 더 있었으면 구현하지 못한 내용 또한 구현을 완료하였을 것 같은데 시간 관리를 잘 하지 못한 점에 대해 아쉬움이 남습니다. 87 | 88 | 89 | # 🙇🏻‍♂️ 마무리 90 | 마지막으로 진행한 미션인만큼 준비도 열심히 하였고 3주간 학습한 내용을 바탕으로 완벽하게 구현하는 것을 목표로 하였습니다. 최종 미션에서 완벽 구현이라는 목표를 이루지 못한 점에 아쉬움이 남지만 3주 전의 저와 현재의 저를 비교해봤을 때 확실히 많은 실력이 늘었다는 점으로 아쉬움을 달래보고자 합니다. 91 | 92 | 지난 3주간 프리코스 기간동안 많은 내용을 배운 것 같습니다. 93 | 3주라는 기간은 누군가에게는 길게 느껴질 기간이지만 저에게 지난 3주는 매우 짧았던 시간으로 느껴졌습니다. 94 | 최종 결과가 어떻게 나올지는 모르겠으나 지난 3주간 최선을 다하여 프리코스에 임하였고 배운 내용이 매우 값져서 어떠한 결과가 나와도 후회하지 않을 것 같습니다. 95 | 96 | 꾸준히 개인 공부를 진행하며 최종 결과를 기다리도록 하겠습니다. 97 | 98 | 최종 결과는 12월 30일입니다! 모두 응원해주세요👍🏻 99 | 100 | ![](https://images.velog.io/images/seongwon97/post/07d102b3-02e8-4663-937f-0a2fe675384d/image.png) -------------------------------------------------------------------------------- /Week1 (21.11.24~30)/1주차 과제 회고.md: -------------------------------------------------------------------------------- 1 | # 프리코스 1주차 과제 2 | ## 🚀 미션 간단 설명 3 | 해당 미션은 우리가 학생시절 자주 하였던 숫자 야구게임을 코드로 구현하는 미션입니다. 4 | 대결은 컴퓨터와 하는 것으로 컴퓨터가 랜덤하게 3자리 수를 만들고 유저는 해당 수를 맞추는 방식으로 진행됩니다. 5 | 6 | 컴퓨터가 만드는 값은 서로 서로 다른 1~9까지의 수로 이루어진 3자리 수의 숫자이며 입력값에 따른 힌트를 기반으로 숫자를 맞춰야합니다. 7 | 8 | ## 🔒 제약사항 9 | - 기능을 구현하기 전에 기능 목록을 만들고, 기능 단위로 커밋 하는 방식으로 진행해야한다. 10 | - 기능 요구사항, 프로그래밍 요구사항, 과제 진행 요구사항을 지켜야한다. 11 | - [Java code convention](https://naver.github.io/hackday-conventions-java)을 지키며 코딩해야한다. 12 | - indent depth가 3이 넘지 않도록 구현해야합니다. 13 | - Scanner, Random API대신 camp.nextstep.edu.missionutils에서 제공하는 Randoms, Console API를 활용해 구현해야 합니다. 14 | - Applicatoin Test에 주어진 테스트 케이스가 모두 통과해야합니다. 15 | 16 | ## 🎓 프리코스 1주차에서 배운점 17 | ### 1. 요구사항 정리 18 | 과제 요구사항에 `Git의 커밋 단위는 앞 단계에서 README.md 파일에 정리한 기능 목록 단위로 추가해라`라는 요구사항이 있어 개발을 하기 전에 개발을 해야할 내용들에 대해 미리 생각을 하며 아래와 같은 구현할 기능 목록을 만들었습니다. 19 | 20 | ![](https://images.velog.io/images/seongwon97/post/d0d8fccd-09bd-4776-9a0d-0eeafdbcf7c2/image.png) 21 | 22 | 요구사항을 개발 전에 정리를 하니 개발에 있어 "다음에는 어떤 내용을 만들어야하지?"라는 내용의 생각과 각각의 기능별 주의해야할 사항, 조건 등을 쉽게 인지하고 코드를 작성할 수 있어 편리함을 느꼈습니다. 23 | 24 | ### 2. Java프로그래밍 코딩 표준 25 | 프리코스를 진행하며 [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html#s4.8.1-enum-classes)에 대해 처음 접하며 해당 내용을 하나씩 세밀하게 번역하고 공부하였습니다. 26 | 27 | 이전 코드를 작성할 때는 코딩 표준이라는 것을 접해본 적이 없어 아무런 생각 없이 코드를 작성하곤 하였습니다. 28 | 29 | 코드도 일정 규칙을 따라 작성하면 가독성이 좋고 변수와 메서드들의 역할을 쉽게 파악할 수 있다는 것을 깨달고 해당 내용을 공부하며 [번역본](https://velog.io/@seongwon97/Google-Java-Style-Guide)을 만들어보기도 하였습니다. 30 | 31 | 처음부터 완벽하게 해당 가이드를 따르며 코딩하기는 어려우나 가이드를 자주 보며 가독성 좋은 코드를 작성하기 위해 노력해야겠다는 다짐을 하였습니다. 32 | 33 | 34 | ### 3. 가독성 좋은 코드 35 | 이전까지 프로그래밍을 할 때 indent depth는 기본적으로 3,4까지 가게되며 복잡한 로직의 경우 주석을 달지 않으면 가끔씩 코딩을 하면서도 내가 작성한 코드가 헷갈릴 때가 있었습니다. 36 | 37 | 과제의 요구사항 중 `함수는 한 가지 일만 하도록 최대한 작게 만들어라`, `indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다.`의 조건을 따르며 프로그래밍을 하다 보니 평상시보다 더 많은 시간이 걸렸지만 코드의 가독성이 좋아지는 것을 배울 수 있었습니다. 38 | 39 | 앞으로 프로그래밍을 할 때도 위의 2가지 조건들을 생각하며 최대한 가독성이 좋은 코드를 작성하도록 습관화시키겠다는 다짐을 하였습니다. 40 | 41 | 42 | ### 4. 크게 관심 갖지 않았던 Test 43 | 이전까지는 Unit Test에 대해서는 개념 정도만 알고 있었는데 해당 1주차 과제를 진행하며 Test의 중요성에 대해 알게 되었습니다. 44 | 45 | 처음에는 주어진 Test코드를 실행시킬 때 `NsTest.java`, `assertRandomNumberInRangeTest`, `assertSimpleTest`와 같은 처음보는 내용대한 호기심으로부터 시작되었습니다. 46 | 처음 보는 코드에 대한 이해를 하고자 [NsTest & Assertion 분석](https://github.com/Seongwon97/woowa_precourse_record/blob/main/Week1%20(21.11.24~30)/Test%EC%BD%94%EB%93%9C%EC%97%90%20%EC%9E%88%EB%8A%94%20NsTest%20%26%20Assertion%20%EB%B6%84%EC%84%9D.md)을 하며 정리를 하였고 그러다보니 다른 여러 메서드에 대해서 Unit Test를 하고자 하는 욕심이 생겼습니다. 47 | 48 | 내가 작성한 메서드들에 대해 Test를 하고자 Unit Test에 대해 먼저 알아보며 [Unit Test정리](https://velog.io/@seongwon97/Unit-Test-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8)를 하였고 몇몇 테스트를 진행하였습니다. 49 | 50 | 그 결과 Input값이 3자리의 수가 입력되어야하는데 내가 작성한 코드는 4자리수 이상의 입력값에 대해서만 Exception을 발생시키고 2자리, 1자리 수에 대해서는 `IllegalArgumentException`을 발생시키지 않는 다는 것을 알 수 있었습니다. 51 | 52 | 테스트 코드를 작성하며 코드 작성시 알아차리지 못하였던 예외상황에 대해서 알게 되며 테스트의 중요성에 대해 다시 한번 깨닫게 되었습니다. 53 | 54 | 55 | 56 | ### 5. Git 커밋 메세지 규약 57 | 58 | 프리코스의 과제 진행 요구사항으로 [the AngularJS commit conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153)를 참고하여 Commit log를 남기라는 요구사항이 있어 커밋 메시지 규약이라는 것에 대해 공부를 하는 기회를 갖게 되었습니다. 59 | ![](https://images.velog.io/images/seongwon97/post/b87aeeb4-ec4e-4065-8d36-f656d372b638/image.png) 60 | 61 | 이전까지 팀 프로젝트와 개인 프로젝트 진행을 할 때는 commit규약을 따로 정하지 않고 다들 원하는 log를 붙이며 커밋을 하였습니다. 그러다보니 확실히 정황히 어떤 내용을 추가하였고 변경하였는지 단번에 알기 힘들었습니다. 62 | 확실히 아래의 이미지를 보면 "alter변경, 텍스트 영어로 변경", "js파일 생성"등 log를 통해 어떤 파일의 내용을 변경하였는지 예측할 수 없으며, 무엇을 변경하였는지 확인을 하려면 커밋 내용을 직접 들어가서 확인을 해야지만 내용을 알 수 있었습니다. 63 | 64 | 65 | 66 | 그러나 프리코스를 진행하며 **the AngularJS commit conventions**을 읽고 공부하며 Commit log의 형식을 통일하였을 때의 장점을 알게 되었고 Commit log의 형식을 바꾸게 되었습니다. 67 | 68 | 그 결과 아래와 같이 어떤 기능을 추가하고 변경한 커밋이며 어떠한 내용을 리펙토링 했는지에 대해 log를 통해 유츄할 수 있게 되었습니다. 이러한 규칙은 여러 팀원들과 함께 큰 프로젝트를 진행할 때 장점을 크게 느낄 수 있을것이라 생각됩니다. 69 | 70 | ![](https://images.velog.io/images/seongwon97/post/c90ed8ec-7ae3-43b9-a0bb-6e7117425b77/image.png) 71 | 72 | > **아쉬운점**😥 : 모든 과제를 제출하고 다시 돌아보니 몇몇 log들의 Type을 잘못 설정한 것들이 있었습니다. 73 | 예를들면 코드의 indent를 맞추는 formatting작업을 하는데 `style`이 아닌 `refactor`를 사용하는 등의 잘못된 log를 남긴 것들이 보였습니다. 74 | 이에 다음 2주차 과제부터는 commit log형식을 더욱 더 신경쓰며 학습을 해야겠다는 다짐을 하였습니다. 75 | 76 | 77 | > 학습을 하며 해당 문서를 번역하고 정리하며 [Git 커밋 메세지 규약 정리 - The AngularJS commit conventions.](https://velog.io/@seongwon97/Git-%EC%BB%A4%EB%B0%8B-%EB%A9%94%EC%84%B8%EC%A7%80-%EA%B7%9C%EC%95%BD-%EC%A0%95%EB%A6%AC-The-AngularJS-commit-conventions)를 작성하였습니다. 78 | 79 |
80 | 81 | ## 최종 후기 82 | 프리코스를 진행한지 1주일도 지나지 않았지만 많은 것을 배울 수 있었습니다. 83 | 84 | indent depth를 2까지 허용하는 요구사항 등을 지키고 그동안 접하지 않은 Git커밋 메시지 규약, Java 코드 컨벤션과 같은 내용들을 공부하며 코딩을 하다보니 내가 작성한 코드들의 가독성이 높아진 것을 확인할 수 있었습니다. 85 | 86 | 프리코스를 진행하며 몇일 사이에 이러한 발전을 할 수 있었는데 남은 기간동안 얼마나 더 많은 학습을 하고 발전을 할 수 있을지 기대가 됩니다. 87 | 88 | 남은 프리코스 기간동안도 많은 것을 학습하며 더욱 더 성장하는 개발자가 되도록 하겠습니다.🔥🔥 89 | -------------------------------------------------------------------------------- /Week3 (21.12.8~14)/싱글톤(Singleton) 패턴이란.md: -------------------------------------------------------------------------------- 1 | # 싱글톤 패턴이란? 2 | > 소프트웨어 디자인 패턴에서 싱글턴 패턴(Singleton pattern)을 따르는 클래스는, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. 이와 같은 디자인 유형을 싱글턴 패턴이라고 한다. 주로 공통된 객체를 여러개 생성해서 사용하는 DBCP(DataBase Connection Pool)와 같은 상황에서 많이 사용된다. 3 | - 출처: [위키피디아](https://ko.wikipedia.org/wiki/%EC%8B%B1%EA%B8%80%ED%84%B4_%ED%8C%A8%ED%84%B4) 4 | 5 | 간단히 설명하면 싱글톤 패턴은 **객체의 인스턴스를 한개만 생성되게 하는 패턴**입니다. 6 | 7 | 이러한 패턴은 주로 프로그램 내에서 하나로 공유를 해야하는 객체가 존재할 때 해당 객체를 싱글톤으로 구현하여 모든 유저 또는 프로그램들이 해당 객체를 공유하며 사용하도록 할 때 사용됩니다. 8 | 9 | 즉, 싱글톤 패턴은 아래와 같은 상황에 사용을 합니다. 10 | - 프로그램 내에서 하나의 객체만 존재해야 한다. 11 | - 프로그램 내에서 여러 부분에서 해당 객체를 공유하여 사용해야한다. 12 | 13 | ## 싱글톤 패턴을 사용하는 이유 14 | 하나의 인스턴스만을 사용하는 싱글톤 패턴의 이점은 다음과 같습니다 15 | 16 | **1. 메모리 측면의 이점** 17 | 싱글톤 패턴을 사용하게 된다면 한개의 인스턴스만을 고정 메모리 영역에 생성하고 추후 해당 객체를 접근할 때 메모리 낭비를 방지할 수 있다. 18 | 19 | **2. 속도 측면의 이점** 20 | 생성된 인스턴스를 사용할 때는 이미 생성된 인스턴스를 활용하여 속도 측면에 이점이 있다. 21 | 22 | **3. 데이터 공유가 쉽다** 23 | 전역으로 사용하는 인스턴스이기 때문에 다른 여러 클래스에서 데이터를 공유하며 사용할 수 있다. 하지만 동시성 문제가 발생할 수 있어 이 점은 유의하여 설계하여야 한다. 24 | 25 | ## 싱글톤 패턴 구현하기 26 | ```java 27 | public class Singleton { 28 | // 단 1개만 존재해야 하는 객체의 인스턴스로 static 으로 선언 29 | private static Singleton instance; 30 | 31 | // private 생성자로 외부에서 객체 생성을 막아야 한다. 32 | private Singleton() { 33 | } 34 | 35 | // 외부에서는 getInstance() 로 instance 를 반환 36 | public static Singleton getInstance() { 37 | // instance 가 null 일 때만 생성 38 | if (instance == null) { 39 | instance = new Singleton(); 40 | } 41 | return instance; 42 | } 43 | } 44 | 45 | ``` 46 | 싱글톤 패턴의 기본적인 구현 방법은 다음과 같습니다. 47 | 48 | 먼저 `private static`으로 Singleton객체의 instance를 선언하고 `getInstance()`메서드가 처음 실행 될 때만 하나의 instance가 생성되고 그 후에는 이미 생성되어진 instance를 return하는 방식으로 진행이 됩니다. 49 | 50 | 여기서 핵심은 `private`로 된 기본 생성자입니다. 생성자를 `private`로 생성을 하며 외부에서 새로운 객체의 생성을 막아줘야 합니다. 51 | 52 | 53 | ```java 54 | // 같은 instance인지 Test 55 | public class Application { 56 | public static void main(String[] args) { 57 | Singleton singleton1 = Singleton.getInstance(); 58 | Singleton singleton2 = Singleton.getInstance(); 59 | 60 | System.out.println(singleton1); 61 | System.out.println(singleton2); 62 | } 63 | } 64 | /** Output 65 | * vendingmachine.Singleton@15db9742 66 | * vendingmachine.Singleton@15db9742 67 | **/ 68 | ``` 69 | 싱글톤 객체를 생성하는 위의 코드를 실행해보면 두 객체가 하나의 인스턴스를 사용하여 같은 주소 값을 출력하는 것을 확인하실 수 있습니다. 70 | 71 | ## Multi-thread에서의 싱글톤 72 | multi-thread환경에서 싱글 톤을 사용하게 된다면 다음과 같은 문제가 발생할 수 있습니다. 73 | 74 | ### 문제점1. 여러개의 인스턴스 생성 75 | Multi-thread환경에서 instance가 없을 때 동시에 아래의 `getInstance()`메서드를 실행하는 경우 각각 새로운 instance를 생성할 수 있습니다. 76 | ```java 77 | public static Singleton getInstance() { 78 | if (instance == null) { 79 | instance = new Singleton(); 80 | } 81 | return instance; 82 | } 83 | ``` 84 | 85 | ### 문제점 2. 변수 값의 일관성 실패 86 | 다음과 같은 코드가 실행이 되었을 때 여러개의 thread에서 `plusCount()`를 동시에 실행을 한다면 일관되지 않은 값들이 생길 수 있습니다. 87 | ```java 88 | public class Singleton { 89 | private static Singleton instance; 90 | private static int count = 0; 91 | 92 | private Singleton() { 93 | } 94 | 95 | public static Singleton getInstance() { 96 | if (instance == null) { 97 | instance = new Singleton(); 98 | } 99 | return instance; 100 | } 101 | 102 | public static void plusCount() { 103 | count++; 104 | } 105 | } 106 | ``` 107 | 108 | ### 해결법 1. 정적 변수선언에서 인스턴스 생성 109 | 이러한 문제는 아래와 같이 `static` 변수로 singleton 인스턴스를 생성하는 방법으로 해결할 수 있습니다. 아래와 같이 초기에 인스턴스를 생성하게 된다면 multi-thread환경에서도 다른 객체들은 getInstance를 통해 하나의 인스턴스를 공유할 수 있습니다. 110 | ```java 111 | public class Singleton { 112 | private static Singleton instance = new Singleton(); 113 | 114 | private Singleton() { 115 | } 116 | 117 | public static Singleton getInstance() { 118 | return instance; 119 | } 120 | } 121 | ``` 122 | ### 해결법 2. synchronzied의 사용 123 | 아래의 코드와 같이 `synchronzied`를 적용하여 multi-thread에서의 동시성 문제를 해결하는 방법입니다. 하지만 **해당 방법은 Thread-safe를 보장하기 위해 성능 저하가 발생**할 것입니다. 124 | ```java 125 | public class Singleton { 126 | public class Singleton { 127 | private static Singleton instance; 128 | 129 | private Singleton() {} 130 | 131 | public static synchronzied Singleton getInstance() { 132 | if(instance == null) { 133 | instance = new Singleton(); 134 | } 135 | return instance; 136 | } 137 | } 138 | } 139 | ``` 140 | 141 | # 결론 142 | 싱글톤 패턴은 메모리, 속도, 데이터 공유 측면에서 이점이 있습니다. 하지만 그렇다고 해서 싱글톤 패턴이 무조건 좋은 것은 아닙니다. 앞서 말했듯이 multi-thread환경에서는 동시성 문제가 발생할 수 있기에 싱글톤 패턴을 사용하고자 한다면 사용하기 앞서 "해당 객체의 인스턴스가 한 개만 존재하여야 하는지?"의 여부와 "사용을 하였을 때의 동시성 문제가 발생하지 않는지"를 체크를 하며 사용해야 할 것 같습니다. 143 | 144 | # Reference 145 | - https://tecoble.techcourse.co.kr/post/2020-11-07-singleton/ 146 | - https://velog.io/@kyle/%EC%9E%90%EB%B0%94-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4-Singleton-Pattern 147 | - https://injae-kim.github.io/dev/2020/08/06/singleton-pattern-usage.html 148 | -------------------------------------------------------------------------------- /Week1 (21.11.24~30)/Test코드에 있는 NsTest & Assertion 분석.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 이번 우테코 프리코스를 진행하며 `NsTest` 클래스의 메서드들과 `Assert` 클래스의 메서드를 활용한 테스트 코드를 실행시키다보니 막히는 부분이 있어 정리를 하게 되었습니다. 3 | 4 | 이번 정리를 통해 앞으로 남은 2주간의 프리코스 과정과 2차 테스트에서의 테스트는 지금보다 쉽게 진행할 수 있을 것이라 믿습니다😁😁 5 | 6 |
7 | 8 | ## camp.nextstep.edu.missionutils.test.NsTest 9 | 아래에서 볼 테스트 코드의 람다식을 보면 `run`메서드를 확인할 수 있습니다. 10 | 해당 메서드에 대해 먼저 알아보도록 하겠습니다. 11 | 12 | ### run 13 | ```java 14 | protected final void run(final String... args) { 15 | command(args); 16 | runMain(); 17 | } 18 | ``` 19 | 20 | #### command 21 | ```java 22 | private void command(final String... args) { 23 | final byte[] buf = String.join("\n", args).getBytes(); 24 | System.setIn(new ByteArrayInputStream(buf)); 25 | } 26 | ``` 27 | command메서드는 `String.join`을 통해 parameter값들 사이에 `\n`을 넣어 배열을 연결시키고 `System.setIn`을 이용하여 콘솔을 통해 입력이 되는 것 처럼 해주는 메서드 입니다. 28 | 29 | #### runMain 30 | ```java 31 | protected abstract void runMain(); 32 | ``` 33 | runMain은 추상 클래스로 테스트할 실제 함수를 통해 override해주고 사용해야합니다. 그래서 실제 ApplicationTest파일을 보면 아래와 같이 재정의된 것을 확인할 수 있습니다. 34 | ```java 35 | // Application.java 36 | @Override 37 | public void runMain() { 38 | Application.main(new String[]{}); 39 | } 40 | ``` 41 | 42 |
43 | 44 | ## camp.nextstep.edu.missionutils.test.Assertions 45 | 46 | 프리코스에서 주어진 Test들은 `assertRandomNumberInRangeTest`와 `assertSimpleTest`메서드를 통해 작성되었습니다. 해당 메서드들은 모두 `camp.nextstep.edu.missionutils.test.Assertions`에 존재하며 두 메서드에 대해 알아보도록 하겠습니다. 47 | 48 | ### assertSimpleTest 49 | ```java 50 | public static void assertSimpleTest(final Executable executable) { 51 | assertTimeoutPreemptively(SIMPLE_TEST_TIMEOUT, executable); 52 | } 53 | ``` 54 | assertSimpleTest는 파라미터로 들어오는 executable을 `SIMPLE_TEST_TIMEOUT`내에 수행할 수 있는지 확인하는 메서드이다. 55 | - 여기서 executable은 우테코 1주차 과제의 테스트 코드를 보면 람다식이 위치한 것을 확인할 수 있습니다. 56 | - SIMPLE_TEST_TIMEOUT은 Assertions클래스 필드에 상수로 정의되어 있으며 실행시간?을 정해주는 변수인것 같습니다. 57 | ```java 58 | private static final Duration SIMPLE_TEST_TIMEOUT = Duration.ofSeconds(1L); 59 | private static final Duration RANDOM_TEST_TIMEOUT = Duration.ofSeconds(10L); 60 | ``` 61 | 62 | #### 우테코에서 주어진 Test code 63 | ```java 64 | @Test 65 | void 예외_테스트() { 66 | assertSimpleTest(() -> 67 | assertThatThrownBy(() -> runException("1234")) 68 | .isInstanceOf(IllegalArgumentException.class) 69 | ); 70 | } 71 | ``` 72 | - `assertSimpleTest()` : 괄호 안에 있는 식이 1초 이내에 실행되는지 Test한다. 73 | - `assertThatThrownBy()` : 해당 메서드는 괄호안에 위치한 람다식 안에서 발생하는 exception을 throw하는 메서드이다. 74 | - `runException("1234")` : 해당 메서드는 해당 parameter를 통해 main메서드를 시행시키고 exception을 잡아내는 함수이다. 위의 코드에서는 1234의 값을 넣고 실행하였을 때 try/catch문으로 exception을 잡아낸다. 75 | - `.isInstanceOf(IllegalArgumentException.class)` : 발생한 exception가 `IllegalArgumentException.class`인지 확인 76 | 77 | 78 |
79 | 80 | ### assertRandomNumberInRangeTest 81 | ```java 82 | public static void assertRandomNumberInRangeTest( 83 | final Executable executable, // 람다식의 실행할 메서드 84 | final Integer value, // Input값들? 85 | final Integer... values 86 | ) { 87 | assertRandomTest( 88 | () -> Randoms.pickNumberInRange(anyInt(), anyInt()), 89 | executable, 90 | value, 91 | values 92 | ); 93 | } 94 | ``` 95 | 해당 메서드는 parameter들을 받아 assertRandomTest를 실행시키는 메서드입니다. 96 | assertRandomTest에 대해 알아보도록 하겠습니다. 97 | 98 | #### assertRandomTest 99 | ```java 100 | private static void assertRandomTest( 101 | final Verification verification, 102 | final Executable executable, 103 | final T value, 104 | final T... values 105 | ) { 106 | assertTimeoutPreemptively(RANDOM_TEST_TIMEOUT, () -> { 107 | try (final MockedStatic mock = mockStatic(Randoms.class)) { 108 | mock.when(verification).thenReturn(value, Arrays.stream(values).toArray()); 109 | executable.execute(); 110 | } 111 | }); 112 | } 113 | ``` 114 | - `final Verification verification` : `MockedStatic.java`에 위치한 interface이다. (확실히 어떠한 역할을 하는지 모르겠으나 `When()`의 parameter로 쓰이는 것으로 보아 MockedStatic 객체의 메서드를 하나씩 실행시키도록 해주는 것 같습니다.) 115 | > Mockito 는 Java 에서 테스트 코드를 작성하는데 자주 사용되는 테스트 프레임워크입니다. 116 | 기존의 Mokito에서는 static method에 대에서는 Mocking을 지원하지 않았으나 업데이트가 되며 현재는 static method도 테스트 할 수 있게 되었습니다. MockedStatic은 static method를 테스트 할 수 있게 해주는 기능들이 담긴 파일입니다. 117 | - `assertTimeoutPreemptively(RANDOM_TEST_TIMEOUT() -> {})` : 해당 메서드는 10초안에 수행을 마쳐야한다. 118 | - `try (final MockedStatic mock = mockStatic(Randoms.class))` : `Randoms` 클래스의 MockedStatic객체 생성 119 | - `mock.when(verification).thenReturn(value, Arrays.stream(values).toArray());` : verification의 method들을 시행하며 value의 값들을 하나씩 return 120 | - `executable.execute();` : 테스트 수행!! 121 | 122 | #### 우테코에서 주어진 Test code 123 | ```java 124 | @Test 125 | void 게임종료_후_재시작() { 126 | assertRandomNumberInRangeTest( 127 | () -> { 128 | run("246", "135", "1", "597", "589", "2"); 129 | assertThat(output()).contains("낫싱", "3스트라이크", "1볼 1스트라이크", "3스트라이크", "게임 종료"); 130 | }, 131 | 1, 3, 5, 5, 8, 9 132 | ); 133 | } 134 | ``` 135 | 136 | # Reference 137 | - https://pjh3749.tistory.com/241 138 | - https://medium.com/@SlackBeck/mock-object%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-85159754b2ac 139 | - https://readystory.tistory.com/190 140 | - https://docs.microsoft.com/ko-kr/dotnet/api/system.string.join?view=net-6.0 141 | - https://www.tutorialkart.com/java/java-system-setin/ 142 | -------------------------------------------------------------------------------- /프리코스 참여 후기.md: -------------------------------------------------------------------------------- 1 | # 우테코란? 2 | 우테코는 **우아한 형제들**에서 개발 인력 양성을 위한 **무료 IT교육 프로그램**입니다. 3 | 저는 이번 웹 백엔드 4기 교육생으로 지원을 하였고 1차 합격자가 되어 프리코스 과정을 진행하게 되었고 벌써 3주라는 시간이 흘러 프리코스 기간이 끝났습니다. 4 | 5 | ![](https://images.velog.io/images/seongwon97/post/0e972a9c-3cc0-4fcb-b49f-31319e2b081f/image.png) 6 | 7 | 3주라는 시간은 누군가에게는 길게 느껴지겠지만 저에게 지난 3주간의 시간은 매우 빠르고 짧은 시간이었으며 엄청난 발전을 한 기간이었다고 생각됩니다. 8 | 9 | 주차별로 과제를 진행하며 학습한 내용은 아래의 주차별 회고록에 기재를 하였기에 이번 포스트에서는 우테코 프리코스를 진행하며 제가 **느낀점들을 중점으로 남기도록 하겠습니다.** 10 | 11 | 12 | ## 📚 프리코스 과정을 진행하며 정리한 자료들 13 | ### 👨🏻‍💻 작성한 과제 코드 14 | - [1주차 미션 - 숫자 야구 게임](https://github.com/Seongwon97/java-baseball-precourse) 15 | - [2주차 미션 - 자동차 경주 게임](https://github.com/Seongwon97/java-racingcar-precourse/tree/Seongwon97) 16 | - [3주차 미션 - 자판기](https://github.com/Seongwon97/java-vendingmachine-precourse/tree/Seongwon) 17 | 18 | ### 📒 회고록 19 | - [1주차 과제 회고](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-1%EC%A3%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C-%ED%9A%8C%EA%B3%A0) 20 | - [2주차 과제 회고](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-2%EC%A3%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C-%ED%9A%8C%EA%B3%A0) 21 | - [2주차 피드백 정리](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-2%EC%A3%BC%EC%B0%A8-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-%EB%A6%AC%EB%B7%B0-%EC%A0%95%EB%A6%AC) 22 | - [3주차 과제 회고](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-3%EC%A3%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C-%ED%9A%8C%EA%B3%A0) 23 | 24 | ### 📕 공부하며 정리한 자료들 25 | - [Google Java Style Guide 번역](https://velog.io/@seongwon97/Google-Java-Style-Guide) 26 | - [Git 커밋 메세지 규약 정리 - The AngularJS commit conventions](https://velog.io/@seongwon97/Git-%EC%BB%A4%EB%B0%8B-%EB%A9%94%EC%84%B8%EC%A7%80-%EA%B7%9C%EC%95%BD-%EC%A0%95%EB%A6%AC-The-AngularJS-commit-conventions) 27 | - [Test코드에 있는 NsTest & Assertion 분석](https://github.com/Seongwon97/woowa_precourse_record/blob/main/Week1%20(21.11.24~30)/Test%EC%BD%94%EB%93%9C%EC%97%90%20%EC%9E%88%EB%8A%94%20NsTest%20%26%20Assertion%20%EB%B6%84%EC%84%9D.md) 28 | - [Unit Test란? (단위 테스트)](https://velog.io/@seongwon97/Unit-Test-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8) 29 | - [Private메서드의 Unit Test](https://velog.io/@seongwon97/Test-Private%EB%A9%94%EC%84%9C%EB%93%9C%EC%9D%98-Unit-Test) 30 | - [MVC 패턴이란?](https://velog.io/@seongwon97/MVC-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80) 31 | - [일급 컬렉션이란?](https://velog.io/@seongwon97/%EC%9D%BC%EA%B8%89-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%B4%EB%9E%80) 32 | - [자바의 Enum 정복하기](https://velog.io/@seongwon97/%EC%9E%90%EB%B0%94%EC%9D%98-Enum-%EC%A0%95%EB%B3%B5%ED%95%98%EA%B8%B0) 33 | - [싱글톤(Singleton) 패턴이란?](https://velog.io/@seongwon97/%EC%8B%B1%EA%B8%80%ED%86%A4Singleton-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80) 34 | 35 | ### 📗 주차별 정리자료 36 | - https://github.com/Seongwon97/woowa_precourse_record 37 | 38 | ## 🐸 나는 우물안의 개구리였다. 39 | 이번 프리코스를 진행하며 매번 느낀 것은 이 세상에는 코딩을 잘하고 뛰어난 사람들이 너무 많이 존재하며 나는 우물 안의 개구리였다는 것을 느꼈습니다. 40 | 41 | 학부 생활을 하며 시험을 볼 때는 같은과 동기들과 전과생, 복전생 등의 같은 학교 학부생들과의 경쟁을 하며 좋은 학점을 받다보니 사회에 나가서도 평균정도는 되지 않을까? 생각했습니다. 42 | 43 | 그러나 프리코스 과정들을 진행하며 다른 지원자들의 깃허브들을 구경하다보니 저는 우물안 개구리인 것을 크게 느꼈습니다..🐸 44 | 45 | 현직 한의사로 일을 하고 계시는데 우테코에 지원 하신분을 비롯하여 대부분의 지원자들의 깃허브를 구경하다보니 "하루 24시간, 같은 시간을 보내며 인생을 살았는데 쌓아온 공부지식, 기술 스텍은 이렇게 다를까?", "이 분들은 바로 취업을 해도 괜찮을 것 같은데??"하는 생각이 많이 들고는 하였습니다. 46 | 47 | 저는 이러한 지원자들의 깃허브를 보며 자극 받고 그 사람들이 쌓아온 기술스텍을 따라잡자는 마음으로 이번 프리코스 과정에서는 2배, 3배로 열심히 임하였던 것 같습니다. 48 | 49 | ## 🦁 우테코의 야생 학습 50 | 51 | > - 소프트웨어 엔지니어가 다루는 문제는 특정일에 머물러있지 않아 야생학습이 필요하다. 그동안 공교육에서 정해진 공부의 틀이 있었다면 우테코에서는 교육자들이 자발적으로 학습을 해야한다. 52 | > - 야생학습에서 살아남으려면 복잡한 상황을 지혜롭게 해결하는 역량, 특정 문화를 해결하는데 필요한 집중력, 끝이 보이지 않는 막막한 현실을 이겨낼 정신력, 함께 문제를 풀기 위한 소프트웨어 스킬 등의 역량이 필요하다. 53 | 54 | 해당 우테코 지원에 앞서 우테코에 대해 알아보던 중 우테코의 학습 방향 중 하나인 야생학습에 대해 정리한 자료입니다. 55 | 56 | 위의 자료와 같이 이번 프리코스는 우테코의 **야생학습**을 경험할 수 있는 기회였습니다. 57 | 우테코 프리코스는 수업이 따로 있는 것이 아니라 3주간 1주일 단위로 요구사항이 주어진 프로그래밍 미션을 하나씩 주고 해당 미션이 끝나면 공통 피드백을 주며 자발적으로 학습을 하는 방법으로 진행되었습니다. 58 | 59 | 저는 프리코스를 진행하며 **공통적으로 주어진 미션을 임하며 내가 자발적으로 얼마나 많은 것을 학습하고 적용할 수 있는지**가 이번 프리코스의 목적이라고 생각되었습니다. 60 | 61 | 확실히 3주간 미션들을 진행하며 Git Commit Convention, Java Style Guide등의 기존에 접하지 못하였던 새로운 학습들을 할 수 있었으며 미션을 수행하다보니 더욱 가독성 좋은 코드, 자바의 특징을 살릴 수 있는 코드를 작성하기 위해 많은 노력을 하였던 것 같습니다. 62 | 또한 Test에 대한 학습 및 MVC 및 싱글톤 등의 여러 공부들도 진행을 하게 되었던 것 같습니다. 63 | 64 | 야생학습이 누군가에게는 잘 맞고 누군가에게는 맞지 않을 수 있으나 3주간 발전한 저의 모습을 보니 저에게는 잘 맞는 학습 방법이었던 것 같습니다. 65 | 66 | ## 👨🏻‍💻 코드리뷰의 장점 67 | 프리코스를 진행하며 가장 좋았던 점은 과제를 Git의 Pull Request방법으로 제출을 하여 다른 지원자들의 코드 리뷰를 할 수 있었다는 점이었습니다. 68 | 69 | 과제가 끝나고 다른 지원자들의 코드 리뷰를 하며 `내가 작성한 코드의 부족함`과 `개선해야할 점`, `몰랐던 기술 및 코드들` 등을 알 수 있었고 이를 반영할 수 있었습니다. 그러다보니 한 주가 지나갈 때마다 작성한 코드가 전 주에 작성한 코드보다 더욱 가독성이 좋아지는 등 발전을 할 수 있었던 것 같습니다. 70 | 71 | 또한 `일급 컬렉션`과 같이 코드에 직접 적용을 하지 못하였더라도 그동안 몰랐던 개발 지식을 하나라도 더 쌓아 갈 수 있는 시간이 됐던 것 같습니다. 72 | 73 | > 🙋🏻‍♂️ 코드 리뷰를 진행하다보니 우테코 프리코스 과정도 우테코 과정에서의 페어 프로그래밍과 같이 팀을 구성하여 서로의 코드 리뷰를 해보도록 하면 좋지 않았을까? 하는 생각도 하게 되었습니다. 각자의 코드를 작성하고 자발적으로 팀 내에서 서로의 코드를 리뷰하게 된다면 프리코스 과정 내에서 더 많은 것들을 배워갈 수 있을 것 같습니다. 74 | 75 | > 🚨 추후 우테코를 지원하기 위해 해당 게시글을 보게된 지원자들도 꼭 과제를 제출했다는 점에서 끝내지 말고 다른 지원자들의 코드 리뷰를 진행해보시길 바랍니다. 76 | 77 | ## 😁 마치며 78 | 취업 시즌이 다가오면 기업들의 공채들뿐만 아니라 **우테코**, SSAFY, Dev Camp등 여러 교육 프로그램 또한 지원을 생각할 것입니다. SSAFY와 다르게 우테코는 2번의 코딩 테스트를 통해 선발되며 최종 코딩테스트에서는 언어 또한 제한이 되게 되며 "지원해도 떨어질 것 같아.."라는 생각과 "1년을 더 공부해야한다고?"라는 생각 때문에 지원을 고민하시는 분이 있을 것입니다. (제 주변의 몇몇 지인들도 그랬어요😥) 79 | 80 | 이러한 고민을 하는 여러분들께 전해드리고 싶은 말은 일단 지원하라고 전해드리고 싶습니다. 81 | 82 | 저는 아직 우테코 과정에 최종적으로 합격한 것은 아니고 현재 프리코스 과정만 진행하였음에도 불구하고 지난 3주간 많은 성장을 하였습니다. 83 | 84 | 저는 지난 3주간의 프리코스 과정을 통해 앞으로 공부를 해야 할 방향과 방법 등 여러가지를 학습할 수 있었습니다. 이것만으로도 충분히 값진 경험을 하였다고 생각합니다. 85 | 86 | 87 | ![](https://images.velog.io/images/seongwon97/post/ae62bb3c-a066-4ef9-b3cd-261dd17ca6e8/image.png) 88 | 89 | 앞으로 남은 과정은 이번주 금요일에 실시하는 최종 코딩테스트만 남았습니다. 90 | 테스트 까지는 기존에 받았던 피드백과 학습 내용을 복습하고 이전에 풀었던 문제들과 풀어보지 못하였던 [java-subway-path-precourse](https://github.com/woowacourse/java-subway-path-precourse) 문제를 풀어보며 준비를 하고자 합니다. 91 | 92 | 테스트 시간이 1~6시로 5시간만 주어지는 만큼 시간이 많이 부족할 수 있으나 최선을 다해서 테스트에 임하도록 하겠습니다. 93 | 94 | 95 | **좋은 기회를 주신 우아한 형제들의 우테코 관계자 분들께 감사함을 표합니다.**🙇🏻‍♂️ 96 | 97 | 98 | -------------------------------------------------------------------------------- /Week3 (21.12.8~14)/3주차 미션 정리.md: -------------------------------------------------------------------------------- 1 | # 🚀 미션 간단 설명 2 | 이번 미션은 우리가 일상생활에서 쉽게 볼 수 있는 자판기를 코드로 구현하는 미션입니다. 3 |
미션 코드의 진행 순서는 다음과 같습니다. 4 | 1. 자판기가 보유한 금액을 입력합니다. 5 | 2. 1에서 입력된 금액으로 자판기는 랜덤하게 동전을 생성한다. (보유한 동전 출력) 6 | 3. 자판기에서 판매할 상퓸 리스트를 입력합니다. 7 | 4. 음료를 구매할 투입 금액을 입력합니다. 8 | 5. 구매할 음료를 입력한다. 9 | 10 | 위의 4,5번을 잔돈이 상품의 최저 가격보다 적거나, 모든 상품이 소진 된 경우까지 반복한다. 11 | 12 | 6. 잔돈을 반환한다. (잔돈이 부족한 경우 반환할 수 있는 금액만 반환한다.) 13 | 14 |
15 | 16 | ## 🔒 제약사항 & 만들어야 할 필수 메서드 17 | ### 1. Coin 18 | 1. 다음 Coin클래스를 활용해야 한다. 19 | ```java 20 | public enum Coin { 21 | COIN_500(500), 22 | COIN_100(100), 23 | COIN_50(50), 24 | COIN_10(10); 25 | 26 | private final int amount; 27 | 28 | Coin(final int amount) { 29 | this.amount = amount; 30 | } 31 | 32 | // 추가 기능 구현 33 | } 34 | ``` 35 | 36 | 37 | ### 2. 입력 38 | #### 2.1. 입력 조건 39 | 1. 상품명, 가격, 수량은 쉼표(`,`)로 구분하며 개별 상품은 대괄호(`[]`)로 묶어 세미콜론(`:`)으로 구분한다. 40 | ``` 41 | [콜라,1500,20];[사이다,1000,10] 42 | ``` 43 | 2. 옳바르지 않는 입력이 들어오면 `IllegalArgumentException`를 발생 시키고 "[ERROR]"로 시작하는 에러 메시지 출력 후 재입력을 받는다. 44 | 3. 사용자의 입력은 camp.nextstep.edu.missionutils.Console의 readLine()을 활용한다. 45 | 4. 입력 받아야 할 값 list 46 | - 자판기가 보유한 금액 47 | - 상품 list 48 | - 투입금액 49 | - 구입할 상품명 50 | 51 | #### 2.2. 잘못된 입력 정리 (예외 상황) 52 | - [자판기가 보유한 금액] 금액이 숫자가 아닌 경우 53 | - [자판기가 보유한 금액] 금액이 음수인 경우 54 | - [자판기가 보유한 금액] 10원으로 나누어 떨어지지 않는 경우 55 | - [상품] 개별 상품이 세미콜론(`:`)을 기준으로 나뉘지 않은 경우 56 | - [상품] 세미콜론(`:`)을 기준으로 개별 상품으로 나누었을 때 각각의 개별상품이 대괄호(`[]`)로 묶이지 않은 경우 57 | - [상품] 개별 상품의 가격 수량이 쉼표(`,`)로 구분되지 않은 경우 58 | - [상품] 개별 상품의 상품명, 가격, 수량 중 값이 누락된 것이 있을 경우 59 | - [상품 - 상품명] 문장의 시작이 공백으로 시작하는 경우 60 | - [상품 - 가격] 가격이 숫자가 아닌 경우 61 | - [상품 - 가격] 가격이 음수인 경우 62 | - [상품 - 가격] 상품 가격이 100원보다 작은 경우 63 | - [상품 - 가격] 상품 가격이 10원으로 나누어 떨어지지 않는 경우 64 | - [상품 - 수량] 수량이 숫자가 아닌 경우 65 | - [상품 - 수량] 수량이 음수인 경우 66 | - [투입금액] 투입 금액이 숫자가 아닌 경우 67 | - [투입금액] 투입 금액이 음수인 경우 68 | - [구매할 상품] 구매할 상품이 없는 상품인 경우 69 | 70 | ### 3. 출력 71 | #### 3.1 출력 조건 72 | - 잔돈은 반환된 동전만 출력한다. 73 | - 예외 상황 발생 시 `[ERROR]`로 시작하는 에러 문구를 출력해야한다. 74 | - 전체적인 출력 예시 75 | ``` 76 | 자판기가 보유하고 있는 금액을 입력해 주세요. 77 | 450 78 | 79 | 자판기가 보유한 동전 80 | 500원 - 0개 81 | 100원 - 4개 82 | 50원 - 1개 83 | 10원 - 0개 84 | 85 | 상품명과 가격, 수량을 입력해 주세요. 86 | [콜라,1500,20];[사이다,1000,10] 87 | 88 | 투입 금액을 입력해 주세요. 89 | 3000 90 | 91 | 투입 금액: 3000원 92 | 구매할 상품명을 입력해 주세요. 93 | 콜라 94 | 95 | 투입 금액: 1500원 96 | 구매할 상품명을 입력해 주세요. 97 | 사이다 98 | 99 | 투입 금액: 500원 100 | 잔돈 101 | 100원 - 4개 102 | 50원 - 1개 103 | ``` 104 | 105 | ### 4. 그 외의 제약사항 106 | - JDK 8 버전 사용 107 | - Indent depth를 2까지만 허용 108 | - 3항 연산자 사용 금지 109 | - 메서드는 최대한 한가지 기능만! 110 | - 메서드의 길이가 15라인을 넘지 않도록 구현 111 | - Else 사용 금지! -> if절에서 return 하는 방식으로 구현하도록! 112 | - Random, Scanner API대신 camp.nextstep.edu.missionutils에서 제공하는 Randoms, Console API를 활용! 113 | - src/test/java 디렉터리의 ApplicationTest에 있는 모든 테스트 케이스가 성공해야 한다. 114 | 115 | >**3주 차 미션의 목표는 여러 개의 클래스를 분리한 후 서로 관계를 맺어 하나의 프로그램을 완성하는 경험을 하는 것이다!** 116 | >
2주차 과제때 부족하였던 클래스 분리와 클래스간의 관계를 맺는 것에 신경을 써보자!! 117 | 118 |
119 | 120 | # 🛠 구현할 기능 목록 121 | - 자판기 클래스 생성 122 | - 자판기를 실행시키는 메서드 생성 123 | - 상품 클래스 생성 124 | - 상품 리스트 클래스 생성 125 | - 사용자 입력관련 메서드 구현 126 | - 잘못된 입력을 판단하는 메서드 구현 127 | - [자판기가 보유한 금액] 금액이 숫자가 아닌 경우 128 | - [자판기가 보유한 금액] 금액이 음수인 경우 129 | - [자판기가 보유한 금액] 10원으로 나누어 떨어지지 않는 경우 130 | - [상품] 개별 상품이 세미콜론(`:`)을 기준으로 나뉘지 않은 경우 131 | - [상품] 세미콜론(`:`)을 기준으로 개별 상품으로 나누었을 때 각각의 개별상품이 대괄호(`[]`)로 묶이지 않은 경우 132 | - [상품] 개별 상품의 가격 수량이 쉼표(`,`)로 구분되지 않은 경우 133 | - [상품] 개별 상품의 상품명, 가격, 수량 중 값이 누락된 것이 있을 경우 134 | - [상품 - 상품명] 문장의 시작이 공백으로 시작하는 경우 135 | - [상품 - 가격] 가격이 숫자가 아닌 경우 136 | - [상품 - 가격] 가격이 음수인 경우 137 | - [상품 - 가격] 상품 가격이 100원보다 작은 경우 138 | - [상품 - 가격] 상품 가격이 10원으로 나누어 떨어지지 않는 경우 139 | - [상품 - 수량] 수량이 숫자가 아닌 경우 140 | - [상품 - 수량] 수량이 음수인 경우 141 | - [투입금액] 투입 금액이 숫자가 아닌 경우 142 | - [투입금액] 투입 금액이 음수인 경우 143 | - [구매할 상품] 구매할 상품이 없는 상품인 경우 144 | - 초기 자판기의 보유한 동전 세팅하는 메서드 구현 145 | - `camp.nextstep.edu.missionutils.Randoms`의 `pickNumberInList()`를 활용 146 | - 음료를 구매하는 메서드 구현 147 | - 음료의 수량 감소 148 | - 투입 금액의 감소 149 | - 구매 상품의 재고가 0인 경우 예외상황 발생 150 | - 잔돈이 상품 구매하려는 상품 가격보다 적은 경우 151 | - 모든 상품 품절 여부 판단 메서드 구현 152 | - 잔돈 반환 메서드 구현 153 | 154 | 155 | 156 | 157 |
158 | 159 | # 📋 구현 체크 리스트 160 | * [ ] 자판기 클래스 생성 161 | * [ ] 자판기를 실행시키는 메서드 생성 162 | * [ ] 상품 클래스 생성 163 | * [ ]상품 리스트 클래스 생성 164 | * [ ] 사용자 입력관련 메서드 구현 165 | * [ ] 입력 값은 `camp.nextstep.edu.missionutils.Console`의 `readLine()`을 활용하였는가? 166 | * [ ] 잘못된 입력을 판단하는 메서드 구현 167 | * [ ] 잘못된 값을 입력할 경우 **IllegalArgumentException**을 발생시켰는가? 168 | * [ ] 잘못된 값에 대해 "[ERROR]"를 통한 메시지를 출력 후 입력을 다시 받았는가? 169 | * [ ] [자판기가 보유한 금액] 금액이 숫자가 아닌 경우 170 | * [ ] [자판기가 보유한 금액] 금액이 음수인 경우 171 | * [ ] [자판기가 보유한 금액] 10원으로 나누어 떨어지지 않는 경우 172 | * [ ] [상품] 개별 상품이 세미콜론(`:`)을 기준으로 나뉘지 않은 경우 173 | * [ ] [상품] 세미콜론(`:`)을 기준으로 개별 상품으로 나누었을 때 각각의 개별상품이 대괄호(`[]`)로 묶이지 않은 경우 174 | * [ ] [상품] 개별 상품의 가격 수량이 쉼표(`,`)로 구분되지 않은 경우 175 | * [ ] [상품] 개별 상품의 상품명, 가격, 수량 중 값이 누락된 것이 있을 경우 176 | * [ ] [상품 - 상품명] 문장의 시작이 공백으로 시작하는 경우 177 | * [ ] [상품 - 가격] 가격이 숫자가 아닌 경우 178 | * [ ] [상품 - 가격] 가격이 음수인 경우 179 | * [ ] [상품 - 가격] 상품 가격이 100원보다 작은 경우 180 | * [ ] [상품 - 가격] 상품 가격이 10원으로 나누어 떨어지지 않는 경우 181 | * [ ] [상품 - 수량] 수량이 숫자가 아닌 경우 182 | * [ ] [상품 - 수량] 수량이 음수인 경우 183 | * [ ] [투입금액] 투입 금액이 숫자가 아닌 경우 184 | * [ ] [투입금액] 투입 금액이 음수인 경우 185 | * [ ] [구매할 상품] 구매할 상품이 없는 상품인 경우 186 | * [ ] 초기 자판기의 보유한 동전 세팅하는 메서드 구현 187 | * [ ] `camp.nextstep.edu.missionutils.Randoms`의 `pickNumberInList()`를 활용하였는가? 188 | * [ ] 음료를 구매하는 메서드 구현 189 | * [ ] 음료의 수량 감소 190 | * [ ] 투입 금액의 감소 191 | * [ ] 구매 상품의 재고가 0인 경우 예외상황 발생 192 | * [ ] 잔돈이 상품 구매하려는 상품 가격보다 적은 경우 193 | * [ ] 모든 상품 품절 여부 판단 메서드 구현 194 | * [ ] 잔돈 반환 메서드 구현 195 | 196 |
197 | 198 | * [ ] 출력 형태를 잘 지켰는가? 199 | * [ ] JDK 8 버전을 사용하였는가? 200 | * [ ] indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현하였는가? 201 | * [ ] 3항 연산자를 사용하지 않고 구현하였는가? 202 | * [ ] 모든 테스트케이스가 성공하는가? 203 | * [ ] 모든 메서드의 길이가 15라인을 넘지 않았는가? 204 | * [ ] Else를 사용하지 않았는가? 205 | * [ ] 클래스 분리하는데 노력을 하였는가? 206 | * [ ] 매직넘버 대신 상수(`static final`)로 코드의 가독성을 높였는가? 207 | * [ ] 클래스를 상수, 멤버 변수, 생성자, 메서드 순으로 작성하며 구현 순서를 지켰는가? 208 | 209 | 210 | -------------------------------------------------------------------------------- /Week1 (21.11.24~30)/Unit Test 학습 내용 정리.md: -------------------------------------------------------------------------------- 1 | # Unit Test란? 2 | Unit test는 프로그래밍을 할 때 소스코드의 특정 모듈(메서드)이 의도된 대로 정확히 작동하는지 검증하는 절차입니다. 다시 말해 작성한 모든 메서드들에 대해서 테스트케이스를 작성하는 것을 의미합니다. 3 | 4 | ## Unit Test의 장점 5 | Unit Test를 진행하게 된다면 하나의 기능을 독립적으로 테스트를 하며 코드 변경으로 인해 문제가 발생하여도 짧은 시간안에 해당 문제를 파악할 수 있습니다. 6 | - 새로운 기능 추가 시 수시로 빠르게 테스트 할 수 있다. 7 | - 리팩토링 시에 안정성을 확보할 수 있다. 8 | - 테스팅에 대한 시간과 비용을 절감할 수 있다. 9 | - 코드에 대한 문서가 될 수 있다. 10 | 11 | 이러한 장점들이 있어 실무에서는 Unit Test를 선호하고 있다고 합니다. 12 | 13 | 14 | ## 좋은 Unit Test를 하는 방법 15 | - 1개의 테스트 함수에 대해서는 assert를 최소화해야한다. 16 | - 1개의 테스트 함수에는 1가지 개념만을 테스트하여야 한다. 17 | 18 | 좋고 깨끗한 테스트 코드는 FIRST라는 5가지 규칙을 따라야 한다. 19 | - Fast: 테스트는 빠르게 동작하여 자주 돌릴 수 있어야 한다. 20 | - Independent: 각각의 테스트는 독립적이며 서로 의존해서는 안된다. 21 | - Repeatable: 어느 환경에서도 반복 가능해야 한다. 22 | - Self-Validating: 테스트는 성공 또는 실패로 bool 값으로 결과를 내어 자체적으로 검증되어야 한다. 23 | - Timely: 테스트는 적시에 즉, 테스트하려는 실제 코드를 구현하기 직전에 구현해야 한다. 24 | 25 | 26 | > 출처: https://mangkyu.tistory.com/143 [MangKyu's Diary] 27 | 28 | 29 | ## Java의 간단한 Unit Test 30 | - Java의 Unit Test는 최근에는 JUnit5와 AssertJ 라이브러리를 많이 사용한다고 합니다. 31 | - JUnit5 : 자바의 단위 테스트를 위한 테스팅 프레임워크 32 | - AssertJ : 자바의 단위 테스트를 돕기 위해 다양한 문법을 지원하는 라이브러리 33 |
34 | - 요즘 Unit test는 주로 한개의 단위를 3가지로 나눠서 처리하는 given-when-then패턴을 사용하는 추세라 한다. 35 | - given(준비) : 어떠한 데이터가 준비되었을 때 36 | - when(실행) : 어떠한 함수를 실행하면! (조건을 지정한다고 생각하면 된다.) 37 | - then(검증) : 어떠한 결과가 나와한다. 38 | - verify : 메서드가 호출된 횟수, 타임아웃 시간 체크를 검사할 때 사용 (부가적) 39 | 40 | > `when()`에서 메서드를 통해 조건을 걸 때 매개변수 값이 어떤 값이라도 상관없으면 `any..`로 시작하는 메서드를 사용하며 특정 값을 넣어야 한다면 `eq()`메서드를 활용합니다. 41 | example ) 42 | ```java 43 | when(cal.add(anyInt(), anyInt())). ~~ 44 | when(cal.add(eq(1), eq(4)). ~~ 45 | ``` 46 | 47 | **옳바른 입력값 테스트** 48 | ```java 49 | @DisplayName("옳바른 입력값 테스트") 50 | @Test 51 | void validInputTest() { 52 | // given 53 | final InputUtil inputUtil = new InputUtil(); 54 | System.setIn(new ByteArrayInputStream("123".getBytes())); 55 | 56 | // when 57 | final List userInput = inputUtil.getPlayerAnswer(); 58 | 59 | // then 60 | Integer[] resultArr = {1, 2, 3}; 61 | List result = Arrays.asList(resultArr); 62 | assertThat(userInput).isEqualTo(result); 63 | } 64 | ``` 65 | 66 | **잘못된 입력값 길이 테스트 (2자리 수)** 67 | ```java 68 | @DisplayName("잘못된 입력값 길이 테스트 (2자리 수)") 69 | @Test 70 | void invalidInputLengthTest1() { 71 | // given 72 | final InputUtil inputUtil = new InputUtil(); 73 | System.setIn(new ByteArrayInputStream("96".getBytes())); 74 | 75 | // when 76 | final RuntimeException exception = assertThrows( 77 | RuntimeException.class, () -> inputUtil.getPlayerAnswer()); 78 | 79 | // then 80 | assertThat(exception.getMessage()).isEqualTo(INPUT_ERROR_LENGTH); 81 | } 82 | ``` 83 | 84 | `@Test`는 해당 메서드가 Unit test라는 것을 명시해주는 어노테이션입니다. 85 | `@DisplayName`를 붙이면 테스트를 실행 하였을 때 나오는 테스트 이름이 바뀌게 됩니다. 86 | 87 | 88 | 89 | ## Stub, Mock의 개념 90 | 프로그래밍을 하게되면 대부분의 객체는 메서드를 시행할 때 다른 객체들과 메시지를 주고받으면서 작업을 하는 것을 알 수 있습니다. 하지만 Unit test는 하나의 모듈에 대한 독립적인 테스트이기 때문에 다른 객체와 메시지를 주고 받는 경우 문제가 발생합니다. 이를 해결하기 위해 메시지를 주고받는 다른 객체 대신에 **Mock Object(가짜 객체)**를 생성하여 테스트합니다. 91 | 또 생성한 Mock Object를 주입하고 어떤 결과를 반환하라고 정해진 결과값을 준비하는데 이것을 **Stub**이라고 합니다. 92 | 93 | > **Mock** : Unit Test를 할 모듈과 메시지를 주고받는 객체를 대신할 가짜 객체이다. 94 | **Stub** : 실제 코드나 아직 준비되지 못한 코드를 호출하여 수행할 때 호출된 요청에 대해 미리 준비해둔 결과를 제공하는 테스트 메커니즘이다. 95 | 96 | ## Mockito란? 97 | Mockito는 개발자가 동작을 직접 제어할 수 있는 가짜(Mock) 객체를 지원하는 테스트 프레임워크입니다. 앞서 말했듯이 개발을 하다보면 객체들간의 의존성이 존재하여 테스트의 어려움이 있습니다. 이러한 문제를 해결하기 위해 Mock Object를 만들어 주입시켜주는데 이를 지원해주는 라이브러리가 Mockito입니다. 98 | 99 | >※ Mockito는 과거에는 static메서드를 지원하지 않는 단점이 있어 PowerMock을 대안으로 사용했으나 Mockito 3.4.0부터는 static method도 지원하고 있습니다. 100 | 101 | ### Mockito사용법 102 | #### 1. Mock 객체의 의존성 주입 103 | Mockito에서 Mock object에 의존성을 주입하기 위해서는 크게 3가지의 어노테이션을 사용합니다. 104 | - `@Mock` : Mock 객체를 만들어 반환해주는 어노테이션 105 | 106 | > `@Mock`을 사용하지 않고 `mock()`메서드를 통해서도 mock객체를 만들 수 있다. 107 | example) 108 | ```java 109 | Hint hint = mock(Hint.class); 110 | ``` 111 | 112 | - `@Spy`: Stub하지 않은 메소드들을 원본 메소드 그대로 사용하는 어노테이션 113 | - `@InjectMocks`: @Mock 또는 @Spy로 생성된 가짜 객체를 자동으로 주입시켜주는 어노테이션 114 | 115 | #### 2. Stub 116 | Mockito에서는 아래의 stub메서드들을 지원하고 있습니다. 117 | `doReturn()`: Mock 객체가 특정한 값을 반환해야 하는 경우 사용 118 | ```java 119 | doReturn(3).when(p).add(anyInt(), anyInt()); 120 | ``` 121 | `doNothing()`: Mock 객체가 아무 것도 반환하지 않는 경우 사용(void) 122 | ```java 123 | @Test 124 | public void example(){ 125 | Person p = mock(Person.class); 126 | doNothing().when(p).setAge(anyInt()); 127 | p.setAge(20); 128 | verify(p).setAge(anyInt()); 129 | } 130 | ``` 131 | `doThrow()`: Mock 객체가 예외를 발생시키는 경우 사용 132 | ```java 133 | @Test(expected = IllegalArgumentException.class) 134 | public void example(){ 135 | Person p = mock(Person.class); 136 | doThrow(new IllegalArgumentException()).when(p).setName(eq("JDM")); 137 | String name = "JDM"; 138 | p.setName(name); 139 | } 140 | ``` 141 | 142 | ### Stub의 doReturn, thenReturn의 차이 143 | Mockito를 사용하다보면 코드들에 `doThrow`, `doReturn`등의 형식이 아닌 `thenReturn()`, `thenThrow()`등의 형식도 볼 수 있을 것이다. 둘의 차이점은 다음과 같습니다. 144 | 145 | **doReturn** 146 | - 실제로 메서드를 호출하고 리턴값을 임의로 정의할 수 있다. 147 | - 메서드를 실제로 수행하여 메서드 작업이 오래걸릴 경우 끝날 때 까지 기다려야한다. 148 | - 실제 메서드를 호출하기 때문에 대상 메서드에 문제점이 있을 경우 발견할 수 있다. 149 | ```java 150 | doReturn(6).when(cal).add(2, 4); 151 | ``` 152 | 153 | **thenReturn** 154 | - 메서드를 실제로 호출하지 않으며 리턴값을 임의로 정의할 수 있다. 155 | - 실제 메서드를 호출하지 않기 때문에 대상 메서드에 문제점이 있어도 알 수 없다. 156 | 157 | ```java 158 | when(cal.add(2, 4)).thenReturn(6); 159 | ``` 160 | 161 |
162 | 163 | # Reference 164 | - https://ko.wikipedia.org/wiki/%EC%9C%A0%EB%8B%9B_%ED%85%8C%EC%8A%A4%ED%8A%B8 165 | - https://mangkyu.tistory.com/143 166 | - https://mangkyu.tistory.com/144 167 | - https://beomseok95.tistory.com/294 168 | - https://jdm.kr/blog/222 169 | - https://medium.com/@SlackBeck/mock-object%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-85159754b2ac 170 | - https://medium.com/@SlackBeck/%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%8A%A4%ED%85%81-test-stub-%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-ff9c8840c1b0 171 | - https://m.blog.naver.com/inho1213/80110527396 172 | - https://royleej9.tistory.com/entry/Mockito-doReturn-thenReturn 173 | - http://daplus.net/java-mockito-doreturn-%EA%B3%BC-when-%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90/ -------------------------------------------------------------------------------- /Week3 이후부터 최종 테스트 이전까지/최종 코딩테스트 대비 1.md: -------------------------------------------------------------------------------- 1 | # 최종 코딩테스트 일정 2 | 우테코 프리코스 기간이 14일 화요일로 종료가 되었고 바로 평상시와 과제 안내처럼 수요일 15시에 최종 코딩테스트 안내 메일을 받았습니다. 3 | 4 | ![](https://images.velog.io/images/seongwon97/post/536d0738-5f15-456d-9502-5931e80418dd/image.png) 5 | 6 | 원래는 오프라인으로 치루는 시험이지만 최근 코로나 확진자가 역대급으로 많이 나오게 되어 지난 3주차 과제 안내에서 말한 바와 같이 올해 최종 코딩테스트는 비대면으로 치루게 되었습니다.. 7 | 8 | 지원자들의 코드 리뷰를 많이 하며 대단하다고 느낀 여러 우테코 지원자들과 우테코 포비님을 직접 뵐 수 있을 기회라고 생각했는데 아쉬운 것 같습니다😥😥 9 | 10 | 11 | # 시험 안내 12 | 시험은 1-6시 예정이며 `Pull Request`는 지원자들이 미리 제출한 지원자의 코드를 보고 테스트를 진행하는 것을 막기 위해 5시 30분 이후로 미션 제출을 할 수 있도록 한 것 같습니다. 13 | 14 | 최종 코딩테스트는 비대면인 만큼 줌으로 지원자와 컴퓨터 모니터가 나오게 라이브로 송출을 하여야 하며 마이크 또한 켜둔 상태로 시험을 치뤄야합니다. 15 | (주말이라 가족들이 모두 있을텐데 미리 말을 해둬야겠어요..😎) 16 | 17 | 그 외의 메인 안내사항으로는 인터넷 구글링이 허용된다는 점이 있는 것 같습니다. 18 | 19 | # 코딩테스트 대비🔥 20 | MVC를 지난 3주차 과제를 하며 익혀 아직 익숙하지 않고 과제 진행을 하면서도 많은 시간들을 소모하였던 저는 최종 테스트에 주어지는 5시간은 시간이 많이 부족할 것이라 생각되어 문제들을 다시 풀어보며 대비를 하고자 마음먹었습니다. 21 | 22 | ## [20211215 수] 코드리뷰 23 | 과제를 받은 수요일인 어제는 평상시와 같이 3주차 과제를 제출한 다른 지원자들의 코드리뷰를 하였습니다. 여러 코드를 보던 중 [조동현 님](https://github.com/woowacourse/java-vendingmachine-precourse/pull/5) 의 코드가 MVC구조가 잘 나뉘어져 있고 여러 기술들을 사용하며 코딩을 한 것 같아 유심히 리뷰하고 배우게 되었습니다. 24 | 25 | 조동현 님의 코드를 상세히 리뷰하며 몇가지 배운 점이 있습니다. 26 | 27 | ### 배운점 1. DTO를 통한 데이터 전달 28 | ![](https://images.velog.io/images/seongwon97/post/8bffa120-8afc-4ad1-adb4-da9b7575d2f0/image.png) 29 | 30 | itemParser를 비롯한 모든 데이터들의 전달을 DTO객체를 생성하여 전달하는 방법으로 코딩하였습니다. 해당 방법은 Spring학습을 하였을 때 배우곤 하였는데 우테코의 백엔드 교육생으로 지원한 만큼 DTO를 활용한 데이터 전달 방법은 좋은 프로그래밍 방식이라고 생각되었습니다. 31 | 32 | ### 배운점 2. 기본 메서드의 재정의 33 | 해당 지원자님은 `equals`, `hashCode`, `toString`과 같은 기본 메서드들을 재정의하여 사용하였습니다. 지난 과제를 할 때 `List`로 상품 객체들을 저장하여 관리하면 해당 List에서 특정 상품 객체를 어떻게 불러와야 할지 방법이 떠오르지 않아서 저는 `HashMap`을 통해 상품을 관리하였습니다. 하지만 `equals`와 `hashCode`를 재정의하여 사용한다면 `List`를 사용해도 상품의 이름을 통해 해당 객체로 접근할 수 있을 것 같습니다. 금요일에 이번 과제를 다시 프로그래밍 해볼 예정인데 그 때는 `equals`, `hashCode`를 재정의하여 사용해봐야겠습니다. 34 | 35 | ![](https://images.velog.io/images/seongwon97/post/9a895727-b760-4b63-9c9c-f53058167246/image.png) 36 | 37 | 또한 지난 과제를 하며 해당 피드백을 놓쳤었는데 금요일 미션을 다시 풀이할 때는 로그 메시지 성격이 강한 자판기 보유 동전같은 것은 `toString`재정의를 통해 출력을 하도록 해야겠습니다. 38 | 39 | 40 |
41 | 42 | ## [20211216 목] 작년 3주차 미션 풀이 43 | 오늘은 지난해 우테코 3기의 프리코스 3주차 미션이었던 [subway-map-precourse](https://github.com/woowacourse/java-subway-map-precourse) 문제를 `fork`한 후 풀어봤습니다. 44 | 45 | 풀어보지 못한 새로운 미션이기도하고 최종 테스트가 얼마 남지 않았기에 오늘은 시간을 측정하며 문제 풀이를 진행하여 보았습니다. 46 | 47 | ### 구현할 내용 정리 48 | 기능 및 구현할 내용 정리는 최종 테스트를 치룬다는 생각을 하며 평상시와 다르게 최소한의 필요한 내용들만 적으려고 해봤습니다. 그렇게 적은 내용은 다음과 같습니다. 49 | 50 | >#### 구현해야 할 내용 51 | - 역 등록기능 만들기 52 | - 중복된 역 등록 금지 53 | - 역 이름은 2글자 이상이어야 한다. 54 | - 역 이름이 공백으로 시작하는 경우 55 | - 역 이름의 입력이 없는 경우 56 | - 역 삭제기능 만들기 57 | - 노선에서도 삭제 필요 58 | - 역 조회기능 (모든 역 출력) 59 |
60 | - 노선 등록 기능 61 | - 노선 이름이 2글자 이상이어야 한다. 62 | - 노선 이름이 공백으로 시작하는 경우 63 | - 노선 이름의 입력이 없는 경우 64 | - 중복된 노선 이름이 존재하는 경우 65 | - 상행 하행 종접 입력 받기 66 | - 이름이 존재하는 역인지 67 | - 둘의 이름이 유요한지 68 | - 둘의 이름이 겹치지 않는지 체크 69 | - 노선 삭제 기능 70 | - 노선 조회 기능 71 |
72 | - 구간 등록 기능 (노선에 역 추가) 73 | - 노선 입력 74 | - 존재하지 않는 노선인지 체크 75 | - 순서 입력 76 | - 숫자인지 체크 77 | - 해당 순서가 가능한 순서인지 체크 78 | - 노선에 중복된 역 등록 금지 79 | 80 | ### 미션을 하며 새롭게 반영한 내용 81 | #### 1. 기본 메서드의 재정의 82 | 이번 미션을 진행하면서는 지난 3주차 자판기 미션에서 놓쳤던 기본 메서드의 재정의를 하였습니다. 아래의 코드는 노선을 나타내는 `Line`클래스의 일부입니다. 83 | 84 | 노선의 이름이 같은 객체는 같은 객체라고 판단을 하기 위해 `equals`와 `hashCode`메서드를 재정의하였으며 해당 미션의 기능중에 노선 정보를 출력하는 기능은 로그 메시지를 남기는 성격이어서 `toString`을 재정의하여 코드를 작성하였습니다. 85 | ```java 86 | @Override 87 | public int hashCode() { 88 | return Objects.hashCode(name); 89 | } 90 | 91 | @Override 92 | public boolean equals(Object obj) { 93 | if (this == obj) 94 | return true; 95 | if (!(obj instanceof Line)) 96 | return false; 97 | 98 | return this.name.equals(((Line) obj).getName()); 99 | } 100 | 101 | @Override 102 | public String toString() { 103 | return "[INFO] " + this.name; 104 | } 105 | ``` 106 | 107 | #### 2. 더욱 체계가 갖춰진 MVC 108 | 코딩은 역시 많이 해봐야 느는 것 같습니다..지난 미션에서는 "이 기능은..service에 가야하나??아니면 Controller에 가야하나..?"하는 고민을 하며 애매한 위치에 작성된 메서드들이 존재하였다면 오늘 프로그래밍한 미션은 한층 더 체계가 갖춰진 것 같습니다. 109 | 110 | 코드를 작성한 체계는 다음과 같습니다. 111 | - **Controller**는 View와 Service에 위치한 메서드를 호출하여 최종적인 단일 기능의 메서드를 생성합니다. (해당 메서드를 호출하면 완벽하게 실행되도록 말이죠😎) 112 | - **Service**는 Repository와 Controller사이에서 비즈니스 로직들이 위치하여 있습니다. 예를 들면 repository의 데이터를 조회하여 입력값이 유요한지를 체크하는 로직과 repository에 최종 데이터 등록, 삭제를 명령하는 메서드들이 들어가 있습니다. 113 | - **Repository**는 실제 DB라 생각하여 Singleton을 적용하여 관리를 하고 값을 return하는 역할만을 하도록 작성하였습니다. 114 | - **domain**은 해당 프로그램에서 사용되는 객체 클래스 파일이 담겨있습니다. 115 | - **utils**에는 앞에서 말한 코드 외의 입력 값이 조건에 맞는 값인지 체크하는 로직이 담긴 `Validator`클래스와 에러 메시지가 담긴 `ExceptionMessage`가 들어있습니다. 116 | 117 | 코드의 구조는 다음과 같습니다. 118 | 119 | ![](https://images.velog.io/images/seongwon97/post/f9a1faeb-f180-4b34-981f-05d3ebc871b2/image.png) 120 | 121 | #### 3. 스트림과 람다식의 사용 122 | 반복적이고 간단하게 나타낼 수 있는 코드의 경우 스트림과 람다식을 활용하여 코드를 간결하게 만들어보려고 노력하였습니다. 123 | ```java 124 | public static void printStationList(List stations) { 125 | System.out.println("\n## 역 목록"); 126 | stations.stream().forEach(station -> System.out.println(station)); 127 | } 128 | ``` 129 | 130 | ### 시험때 반영할 내용 정리 131 | 1. 구현해야 할 내용은 과제를 진행할 때 처럼 너무 깊게 정리하지 말고 일단 생각나는 기능과 예외 상황들만 정리하자! (미션을 진행할 때는 과제 및 구현내용 정리를 하는데 하루를 투자한 날도 있습니다..😵) 132 | 2. 람다식과 Stream을 활용하자!! 133 | 3. 큰 기능별로 Controller와 Service를 만들어 관리를 하자! 134 | 4. Repository는 싱글톤으로 관리하자! 그리고 Repository는 실제 DB 테이블이라 생각하고 관리하며 데이터 return만을 하자! (비즈니스 로직은 가능하면 Service에서!) 135 | 5. 로그 느낌의 메시지들은 객체들의 `toString`을 재정의하여 사용하자! 136 | 6. `equals`, `hashCode`들도 활용하자! 137 | 138 | ### 구현 후기 139 | 문제를 풀이하다보니 올해 3주차 과제로 나왔던 자판기 미션과 비교를 하였을 때 문제에서 구현하여야 할 내용이 많았던 문제였던 것 같습니다. 기능이 크게 **역 관련 기능**, **노선 관련 기능**, **지하철 구간 추가 기능**으로 나뉘게 되고 문제에서 초기 설정해야하는 역과 노선의 데이터들과 해당 기능들을 통합하여 main에서 한번에 실행시켜야하다보니 시간이 부족하였던 것 같습니다. 140 | 141 | 결론부터 말하자면 해당 미션을 요구사항 정리부터 문제 풀이 완료까지 소요된 시간은 **6시간 5분**이 소요되었습니다. 미션 종료 시간인 5시간이 되었을 때는 개별 기능들까지는 완성을 하였는데 해당 기능들의 통합을 하지 못하였습니다.. 142 | 143 | 최종 미션이 해당 미션처럼 한가지 기능이 아닌 여러 기능을 구현하고 해당 기능을 통합하는 미션이 나온다면 시간부족을 피하지 못할 것 같습니다😥😥 144 | 145 | 그래도 좋은 소식은 지난 3주차 미션기간동안 MVC방식으로 미션을 2번 실행해봐서 그런지 속도가 확실히 빨라진 것 같습니다. 자판기 미션을 처음 풀이할 당시 대략 12시간의 시간이 걸렸던 것 같은데 오늘 풀이한 미션은 훨씬 많은 기능을 구현하였는데도 6시간이 걸렸으니 많이 발전한 것 같습니다. 146 | 147 | 시험을 준비할 기간은 이제 17일 하루밖에 남지 않았습니다. 148 | 작년 최종 문제가 3주차 미션의 내용과 연관되어 나온 만큼 올해도 그럴 것이라 예측을 하며 내일은 3주차 미션이었던 자판기 문제를 처음부터 다시 프로그래밍해보려합니다. 149 | 150 | **후회하지 않는 결과를 만들기 위해 남은 하루도 노력하겠습니다🔥🔥🔥** 151 | 152 | > 오늘 작성한 지하철 노선도 미션 코드는 다음 링크를 통해 확인하실 수 있습니다.
153 | > [지하철 노선도 미션](https://github.com/Seongwon97/java-subway-map-precourse/tree/Seongwon97) 154 | 155 | -------------------------------------------------------------------------------- /Week3 (21.12.8~14)/Enum 정복하기.md: -------------------------------------------------------------------------------- 1 | 우테코 프리코스 3주차 과제의 요구사항 중 아래의 enum코드를 사용하라는 조건을 접하게 되었습니다. 2 | 3 | ```java 4 | public enum Coin { 5 | COIN_500(500), 6 | COIN_100(100), 7 | COIN_50(50), 8 | COIN_10(10); 9 | 10 | private final int amount; 11 | 12 | Coin(final int amount) { 13 | this.amount = amount; 14 | } 15 | 16 | // 추가 기능 구현 17 | } 18 | ``` 19 | 20 | 기존까지는 enum을 사용을 크게 하지 않고 간단하게 보기 항목을 정의할 때만 사용을 하여 조건으로 주어진 코드는 새롭기도 하고 이해하기도 어려웠습니다. 코드를 한참 찾아보고 다른 지원자의 코드를 봐도 처음에 이해가 어려웠어서 enum을 이번 기회에 새롭게 공부를 하며 나만의 지식으로 만들기 위해 정리를 해보고자 합니다. 21 | 22 | # enum class란? 23 | enum은 Enumeration의 줄임말로 **서로 연관된 상수들의 집합**이라는 의미를 갖습니다. 우리가 일반적으로 상수(constant)를 정의할 때는 `static final`을 사용하여 정의합니다. 하지만 이러한 기존의 상수는 클래스 내에서 선언하는 부분은 네이밍이 겹칠 수 있고 불필요하게 상수가 많아진다는 단점이 발생합니다. 자바 1.5버전 부터는 `Enum`이 새로 생겨 `static final`로 만들어질 수 있는 단점들을 보완할 수 있게 되었습니다. 24 | 25 | 26 | ## enum의 이점 27 | 1. 코드가 단순해지며, 가독성이 좋아진다. 28 | 2. 인스턴스 생성과 상속을 방지하여 상수의 타입 안정성이 보장됩니다. 29 | 3. enum class를 사용해 새로운 상수들의 타입을 정의함으로정의한 타입 이외의 타입을 가진 테이터 값을 컴파일시 체크한다. 30 | 4. 키워드 enum을 사용하기 때문에 구현의 의도가 열거임을 분명하게 알 수 있다. 31 | 32 | > 출처 : https://limkydev.tistory.com/50 33 | 34 | ## enum의 특징 35 | #### 1. 클래스를 상수처럼 사용할 수 있다. 36 | ```java 37 | public enum Coin { 38 | COIN_500(500), 39 | COIN_100(100), 40 | COIN_50(50), 41 | COIN_10(10); 42 | 43 | private final int amount; 44 | 45 | Coin(final int amount) { 46 | this.amount = amount; 47 | } 48 | } 49 | ``` 50 | 우테코 프리코스의 코드를 보면 `default`생성자는 `private`으로 되어 있는 것을 확인할 수 있습니다. 그리고 이를 `public`으로 변경하는 경우 컴파일 에러가 발생합니다. 51 | 52 | ![](https://images.velog.io/images/seongwon97/post/ee3c7c4d-a942-4bfd-9f43-d3728f48fd25/image.png) 53 | 54 | 이는 다른 상수들이 클래스 로드 시점에 생성되는 것처럼 enum 또한 생성자가 존재하지만 클래스가 로드되는 시점에서 생성되기에 임의로 생성해서 사용할 수 없는 것입니다. 55 | 56 | 사용을 할 때는 `Coin.COIN_500`과 같이 사용하면 됩니다. 57 | 58 | 59 | #### 2. Enum 클래스를 구현하는 경우 상수 값과 같이 유일하게 하나의 인스턴스가 생성되어 사용된다. 60 | - enum은 `싱글톤`형태로 하나의 애플리케이션 안에서 하개의 인스턴스로 생성되어 사용됩니다. 그래서 enum에 인스턴스 변수를 추가하는 것은 위험할 수 있습니다. 61 | 62 | #### 3. 서로 관련 있는 상수 값들을 모아 enum으로 구현하는 경우가 유용하다. 63 | - 저는 해당 내용이 enum을 사용을 하는 가장 큰 이유라고 생각됩니다. 64 | 65 | #### 4. 클래스와 같은 문법 체계를 따른다. 66 | - 클래스의 형태를 보이고 있어 관련 로직들을 enum클래스 내에서 관리할 수 있습니다. 67 | 68 | #### 5. 상속을 지원하지 않는다. 69 | - enum은 `java.lang.enum`의 상속을 받기 때문에 다른 상속을 지원하지 않는다. 70 | 71 | ## Enum의 API들 72 | ### 1. values() 73 | 74 | ![](https://images.velog.io/images/seongwon97/post/597c52e6-080b-4ab4-83c4-ef814463f07c/image.png) 75 | 76 | - `values()`는 Enum 클래스가 갖고 있는 인스턴스가 담긴 배열을 반환하는 작업을 합니다. 77 | 위의 코드를 보면 해당 enum이 가진 모든 인스턴스 값들을 반환하여 출력되는 것을 확인할 수 있습니다. 78 | 79 | 80 | ### 2. valueOf() 81 | - `valueOf()`는 string의 입력을 받아 일치하는 인스턴스의 이름이 존재한다면 해당 인스턴스를 반환해줍니다. 82 | 83 | ![](https://images.velog.io/images/seongwon97/post/46a80606-92ce-48c1-be7a-068ab39f026c/image.png) 84 | 85 | ### 3. toString() 86 | - enum에서 `toString()`은 인스턴스의 이름을 리턴합니다. 87 | 88 | ### 4. name() 89 | - 해당 메서드 또한 인스턴스의 이름을 리턴해줍니다. 90 | 91 | ## 프리코스 3주차에서의 Enum활용 92 | 우테코 프리코스 3주차 자판기 미션을 활용하면서 저는 enum클래스를 다음과 같이 작성하였습니다. 코드를 살펴보면 앞서 말한 enum의 특징인 enum은 클래스와 같은 문법 체계를 따르고 관련있는 상수들을 모아서 관리를 한 것을 확인하실 수 있습니다. 93 | ```java 94 | public enum Coin { 95 | COIN_500(500), 96 | COIN_100(100), 97 | COIN_50(50), 98 | COIN_10(10); 99 | 100 | private final int amount; 101 | 102 | 103 | Coin(final int amount) { 104 | this.amount = amount; 105 | } 106 | 107 | public static List getCoinList() { 108 | return Arrays.stream(Coin.values()) 109 | .sequential() 110 | .collect(Collectors.toList()); 111 | } 112 | 113 | public static List getCoinValueList() { 114 | return Arrays.stream(Coin.values()) 115 | .map(Coin::getAmount) 116 | .sequential() 117 | .collect(Collectors.toList()); 118 | } 119 | 120 | public static List getAvailableCoinValueList(int remainMoney) { 121 | return Arrays.stream(Coin.values()) 122 | .filter(coin -> coin.getAmount() <= remainMoney) 123 | .map(Coin::getAmount) 124 | .sequential() 125 | .collect(Collectors.toList()); 126 | } 127 | 128 | public int getAmount() { 129 | return amount; 130 | } 131 | 132 | public static Coin getEnumCoin(int amount) { 133 | return Arrays.stream(Coin.values()) 134 | .filter(coin -> coin.getAmount() == amount) 135 | .sequential().collect(Collectors.toList()).get(0); 136 | } 137 | } 138 | ``` 139 | 140 | **getAvailableCoinValueList(int remainMoney)**은 enum 클래스의 인스턴스 중에서 파라미터로 넘어온 값보다 작거나 같은 값들의 인스턴스들을 list로 반환하는 메서드 입니다. 141 | ```java 142 | public static List getAvailableCoinValueList(int remainMoney) { 143 | return Arrays.stream(Coin.values()) 144 | .filter(coin -> coin.getAmount() <= remainMoney) 145 | .map(Coin::getAmount) 146 | .sequential() 147 | .collect(Collectors.toList()); 148 | } 149 | ``` 150 | 151 | **getCoinList(), getCoinValueList()**는 enum의 기본 API인 `values()`는 enum 인스턴스의 배열을 return 해주는데 이를 stream을 사용하여 각각 coin 인스턴스와 인스턴스의 값을 list로 반환하도록 커스텀한 메서드 입니다. 152 | ```java 153 | public static List getCoinList() { 154 | return Arrays.stream(Coin.values()) 155 | .sequential() 156 | .collect(Collectors.toList()); 157 | } 158 | 159 | public static List getCoinValueList() { 160 | return Arrays.stream(Coin.values()) 161 | .map(Coin::getAmount) 162 | .sequential() 163 | .collect(Collectors.toList()); 164 | } 165 | ``` 166 | 167 | **getEnumCoin(int amount)**메서드는 인스턴스의 값에 해당하는 인스턴스를 return하도록 커스텀한 메서드 입니다. 168 | ```java 169 | public static Coin getEnumCoin(int amount) { 170 | return Arrays.stream(Coin.values()) 171 | .filter(coin -> coin.getAmount() == amount) 172 | .sequential().collect(Collectors.toList()).get(0); 173 | } 174 | // ex) 500을 대입하면 COIN_500을 return 175 | ``` 176 | 177 | ## 정리 178 | enum은 연관된 상수들을 관리하는 집합으로 이를 사용하면 코드의 가독성, 안정성 등이 올라갑니다. 또한 enum은 클래스와 같은 문법 체계를 사용하여 enum의 기본 사용법만 알고 있다면 Java프로그래밍을 하는 누구나 쉽게 사용할 수 있을 것입니다. 179 | 180 | enum은 이전까지 프로그래밍을 하여 사용 빈도가 적었던 것은 사실입니다. 하지만 이번 기회에 enum의 기본적인 형태와 사용법을 알게 되었고 앞으로는 이를 활용하여 더욱 가독성 좋은 코드를 작성하도록 노력해보고자 합니다. 181 | 182 | > ※ 해당 post는 [카일님](https://velog.io/@kyle/%EC%9E%90%EB%B0%94-Enum-%EA%B8%B0%EB%B3%B8-%EB%B0%8F-%ED%99%9C%EC%9A%A9) 의 포스트를 참조하며 작성하였습니다. 183 | 184 | 185 | # Reference 186 | - https://velog.io/@kyle/%EC%9E%90%EB%B0%94-Enum-%EA%B8%B0%EB%B3%B8-%EB%B0%8F-%ED%99%9C%EC%9A%A9 187 | - https://limkydev.tistory.com/50 -------------------------------------------------------------------------------- /Week3 (21.12.8~14)/2주차 피드백 & 다른 지원자 코드 리뷰.md: -------------------------------------------------------------------------------- 1 | # 3주차 과제를 하기 앞서... 2 | 1주차 과제를 한 후 공통 피드백을 받았을 때는 [2주차 과제 회고](https://velog.io/@seongwon97/%EC%9A%B0%ED%85%8C%EC%BD%94-%ED%94%84%EB%A6%AC%EC%BD%94%EC%8A%A4-2%EC%A3%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C-%ED%9A%8C%EA%B3%A0) 정리에 간단하게 1주차 과제 피드백 리뷰를 정리하였습니다. 3 | 4 | 지난주와 같이 이번주에 2주차 과제 피드백을 받게 되었고 피드백을 읽다보니 지난주 과제에 지켜지지 않은 점들이 보여 따로 정리를 하게 되었습니다. 또한 다른 지원자들의 코드와 제가 작성한 코드를 비교하면서도 이번 3주차 과제를 하기 앞서 알아두면 좋은 개발 지식, 개선해야할 점 등을 먼저 정리하고자 합니다. 5 | 6 | # 2주차 피드백 정리 7 | 1. 기능 목록 구현을 할 때 클래스의 이름, 메서드의 input/output은 언제든지 변경될 수 있기에 너무 세세한 부분까지 정리하기보다 구현해야 할 기능 목록을 정리하는데 집중하여라!! 또한 **예외상황도 정리**하도록 노력하여라! 8 | 2. 문자열, 숫자 등으로 사용되는 매직 넘버는 상수(`static final`)으로 이름을 부여해 의도를 드러내야한다. 9 | 3. 메서드나 변수명 등의 이름은 축약하지 말고 의도를 드러내도록 하여라. 10 | 4. 메서드 라인의 기준 15라인은 공백 라인도 포함이 된다. 11 | 5. commit메시지에 `#번호`는 이슈 또는 Pull Request를 참조할 때 사용하는 것이다. 12 | 6. 예외 상황을 고려해 프로그래밍하는 습관을 들이도록 하여야한다. 13 | 7. 주석은 꼭 필요한 경우에만 남긴다. 14 | 8. git을 통해 관리할 자원에 대해서 고민하여라 15 | 9. Pull Request를 보내기 전에는 브랜치를 확인하여라. 16 | 10. 메서드를 구현하기 앞서 Java api에서 제공을 하는 기능인지 검색을 하며 java api를 적극 활용하여라. 17 | 11. 배열 대신 List,Set,Map등의 java Collection을 사용하여라! 18 | 12. 객체에 메시지를 보내라 19 | 13. 필드(인스턴스 변수)가 많은 것은 객체의 복잡도를 높이고 버그 발생 가능성을 높일 수 있어 필드의 수를 최소화 하여라! 20 | 14. 비즈니스 로직과 UI로직이 한 클래스에 있는 것은 단일 책임 원칙에도 위배됨으로 분리하여여야한다. 21 | 22 | # 2주차 피드백에서 지키지 못한 것들 23 | 24 | ## 1. 매직 넘버는 상수(`static final`)으로 이름을 부여해 의도를 드러내야한다. 25 | 26 | 27 | 해당 피드백은 1주차 피드백에서도 존재하였던 피드백입니다. 1,2주차 과제를 진행하며 상수를 적극 활용하였으나 다른 지원자의 코드를 리뷰하다보니 제가 지금까지 생각한 매직넘버의 기준에 잘못된 것이 있다는 것을 깨닫고 2주차 과제에서 상수를 적용하지 못한 코드가 존재하였습니다. 28 | 29 | ### 1.1. 매직넘버의 잘못된 기준 30 | 31 | ```java 32 | // 2주차 과제에 작성되었던 코드의 일부 33 | public static final int INITIAL_VALUE = 0; 34 | 35 | private static void checkInvalidAttempNum(String attempStr) { 36 | for (int i = INITIAL_VALUE; i < attempStr.length(); i++) { 37 | if (!Character.isDigit(attempStr.charAt(i))) { 38 | System.out.println(ERROR_INVALID_ATTEMP); 39 | throw new IllegalArgumentException(ERROR_INVALID_ATTEMP); 40 | } 41 | } 42 | } 43 | ``` 44 | 지금까지 코드에 존재하는 모든 숫자들은 모두 매직 넘버라고 생각했습니다. 그리하여 `for`문 안에서 `int i=0`과 같은 초기화를 할 때도 상수를 사용하였습니다. 45 | 46 | 하지만 `for`문 안에서의 `int i=0`의 0의 의미는 모두가 알 수 있어 `int i = INITIAL_VALUE`로 바꾸는 것은 의미 없는 상수 변환이라는 것을 깨달았습니다. 47 | 48 | > **상수 변환을 할 때 숫자 1을 ONE으로 이름을 짓는 것과 같은 의미없는 상수 변환은 피하도록 하자.** 49 | 출처: https://javabom.tistory.com/28 50 | 51 | ### 1.2. 상수 변환을 놓친 코드 52 | ```java 53 | // 2주차 과제에 작성되었던 코드의 일부 54 | public static void printByAttemp(List carList) { 55 | for (Car car : carList) { 56 | System.out.print(car.getName() + " : "); 57 | for (int i = INITIAL_VALUE; i < car.getPosition(); i++) { 58 | System.out.print("-"); 59 | } 60 | System.out.println(); 61 | } 62 | System.out.println(); 63 | } 64 | ``` 65 | 해당 코드를 작성할 때 출력에 사용될 ` : `, `-`, `,`는 간단한 문자이기에 상수 변경을 하지 않아도 되겠지~하고 넘어갔었습니다. 66 | 67 | 지금 다시 생각해보면 정말 안일한 생각이었던 것 같습니다. 좋은 프로그래밍 코드란 다른 누군가가 보더라도 쉽게 이해하는 코드라 생각을 하였는데 제가 작성한 코드는 우테코 과제를 하였던 지원자들 외의 다른 사람들이 봤을 때 출력문의 ` : `, `-`, `,`는 코드를 실행시키기 전까지 무엇을 의미하는지 파악하기 힘들기 때문입니다. 68 | 69 | 해당 문자들은 아래와 같이 상수로 변경하여 쓰는게 옳았다는 것을 깨달으며 3주차 과제를 비롯한 앞으로의 프로그래밍에서는 이러한 실수를 하지 않겠다는 다짐을 하였습니다. 70 | ```java 71 | private static final String DELIMITER_FIELD = " : "; 72 | private static final String DELIMITER_WINNER = ", "; 73 | private static final String CAR_STATUS_BAR = "-"; 74 | ``` 75 | ※ 해당 상수 코드는 우테코 프리코스 지원자인 [2012monk](https://github.com/2012monk) 님의 코드에서 발췌하였습니다. 76 | 77 | 78 | ## 2. 객체에 메시지를 보내라 79 | ![](https://images.velog.io/images/seongwon97/post/30bb352a-c1ac-43f8-b850-df9d5797efdc/image.png) 80 | 81 | 이전까지 작성한 코드들은 하나같이 객체에 메시지를 보내는 것이 아닌 get을 통해 객체의 데이터를 꺼내왔기 때문에 해당 피드백의 내용을 보고는 충격을 받았습니다. 82 | 83 | 아래의 코드는 제가 2주차 과제에 우승자들을 찾기 위해 만든 메서드입니다. 84 | 해당 코드를 보면 모두 `getPosition()`을 통해 객체에 메시지를 보내는 것이 아닌 값을 받아오는 형태로 구현된 것을 확인할 수 있습니다. 85 | 86 | ```java 87 | // 2주차 과제에 작성되었던 코드의 일부 88 | private static ArrayList findWinnerList(List carList) { 89 | HashMap> rankMap = new HashMap<>(); 90 | int maxPosition = INITIAL_VALUE; 91 | 92 | for (Car car : carList) { 93 | int carPosition = car.getPosition(); 94 | maxPosition = Math.max(maxPosition, carPosition); 95 | 96 | if (!rankMap.containsKey(carPosition)) { 97 | rankMap.put(carPosition, new ArrayList<>()); 98 | } 99 | rankMap.get(carPosition).add(car.getName()); 100 | } 101 | return rankMap.get(maxPosition); 102 | } 103 | ``` 104 | 105 | 위의 코드를 피드백을 반영한 코드의 형태로 변경을 해보았습니다. 106 | 기존의 maxPosition의 판단은 `getPosition()`을 통해 값을 불러와서 판단을 하였다면 변경한 코드는 car에 `maxDistance`의 값을 메시지로 보내어 결과 판단을 하도록 변경하였습니다. 107 | 108 | ```java 109 | private static ArrayList findWinnerList(List carList) { 110 | 111 | int maxDistance = INITIAL_VALUE; 112 | for (Car car : carList) { 113 | if (!car.isNewMaxPosition(maxDistance)) 114 | continue; 115 | 116 | if (car.isSameMaxPosition(maxDistance)) { 117 | // 기존 winners객체에 해당 car를 추가 118 | continue; 119 | } 120 | 121 | // 새로운 winners객체를 만드는 코드 122 | } 123 | // winners객체 return 124 | } 125 | ``` 126 | 127 | 코드를 변경하다보니 이번 과제에서는 클래스의 분리가 많이 부족하다는 것을 새로 느끼게 되었습니다. 2주차 과제의 연습 목표가 **클래스 분리**라 클래스를 많이 분리하였다고 생각하였음에도 불구하고 클래스 분리가 부족했다는 것을 느끼었습니다. 다음 3주차 미션에서는 클래스 분리를 더욱 열심히 해보고자 합니다. 128 | 129 | ## 3. 비즈니스 로직과 UI 로직을 분리해라 130 | 코드를 작성할 때 비즈니스 로직과 UI로직을 한 클래스가 담당하지 않도록 하여야 한다는 피드백을 받았습니다. 해당 피드백을 받고 저의 코드를 보니 아래와 같이 우승자 리스트를 찾는 비즈니스 로직과 해당 결과를 출력하는 UI로직이 한개의 클래스에 모여 있는 것을 확인할 수 있었습니다. 131 | 132 | 📌 이번 3주차 미션을 수행할 때는 지난주 과제 제출 이후 공부하였던 [MVC패턴](https://velog.io/@seongwon97/MVC-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80) 을 적용하도록 노력하여 비느지스 로직과 UI로직을 분리해보고자 합니다. 133 | 134 | ```java 135 | public class PrintUtils { 136 | public static void printFinalResult(List carList) { 137 | 138 | ... 139 | } 140 | 141 | private static ArrayList findWinnerList(List carList) { 142 | 143 | ... 144 | } 145 | } 146 | ``` 147 | 148 | 149 | 150 | # 다른 지원자의 코드를 보고 찾은 개선해야할 점 151 | ## 1. MVC 패턴을 사용해보자 152 | 153 | ![](https://images.velog.io/images/seongwon97/post/3c6a1b5d-4c82-4604-b3e2-a0b4215786e9/image.png) 154 | 155 | 우테코 프리패스 과정을 진행하며 보다 나은 코드와 코드의 구조를 만들고자 다른 지원자들의 코드 리뷰를 하며 제가 작성한 코드와 비교를 해봤습니다. 156 | 다른 지원자들의 제출 코드들을 보니 많은 지원자들이 MVC패턴을 적용하여 과제를 진행한 것을 확인할 수 있었습니다. 157 | MVC패턴은 이전에 스프링 프레임워크 학습을 하며 사용을 하였으나 스프링 프로젝트 외의 다른 프로젝트들에 적용을 할 생각을 하지 못하였습니다. 158 | 159 | MVC패턴을 적용하여 기능별로 코드를 분리해 가독성과 코드의 재사용을 증가시켜보고자 합니다. 160 | 161 | > MVC패턴 정리자료 : https://velog.io/@seongwon97/MVC-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80 162 | 163 | 164 | ## 2. 클래스를 더욱 분리해보자 165 | 앞서 말했듯이 2주차 과제의 연습 목표가 **클래스 분리**인 만큼 제 나름대로 과제를 진행하며 클래스를 분리하였습니다. 하지만 피드백을 받고 다른 지원자들의 제출 코드를 보니 "이런 것까지 클래스 분리를 한다고??😵"라는 생각이 들 정도로 클래스를 더욱 나눌 수 있다는 것을 배운 것 같습니다. 166 | 167 | 또한 클래스를 많이 분리한 코드를 보니 가독성이 더 좋다는 것을 느꼈습니다. 168 | 169 | 3주차 과제는 마지막 과제인 만큼 클래스를 최대한 분리하여 코드를 작성해보고자 합니다. 170 | 171 | ## 3. 일급 컬렉션을 사용해보자 172 | [jayjaehunchoi](https://github.com/jayjaehunchoi) 님의 과제 제출 코드와 [woowafreecourse_study](https://github.com/jayjaehunchoi/woowafreecourse_study) 자료를 보며 일급 컬렉션이라는 용어를 처음 접하게 되었습니다. 173 | 174 | 일급 컬렉션 내용도 3주차 과제를 진행하며 적용할 수 있는 부분이 있으면 적용하며 보다 좋은 코드를 작성하기 위해 노력하고자 합니다. 175 | 176 | > 일급 컬렉션 정리 자료: https://velog.io/@seongwon97/%EC%9D%BC%EA%B8%89-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%B4%EB%9E%80 177 | 178 | -------------------------------------------------------------------------------- /Week1 (21.11.24~30)/Git 커밋 메세지 규약 정리 - The AngularJS commit conventions.md: -------------------------------------------------------------------------------- 1 | # 목표 2 | - 스크립트로 CHANGELOG.md를 작성할 수 있다. 3 | - **git bisect**를 사용하여 중요하지 않은 커밋을 무시할 수 있다. (Formatting과 같은 중요한 커밋은 아닌 경우) 4 | - 커밋 기록 탐색시 더 좋은 정보를 제공한다. 5 | 6 | > **※ git bisect** 7 | 커밋의 특정 범위 내에서 이진 탐색을 통해 문제가 발생한 최초의 커밋을 찾는데 도움을 주는 git의 기능이다. 8 | 9 |
10 | 11 | # CHANGELOG.md 생성 12 | - 새로운 기능 (new Feature) 13 | - 버그 수정 (bug fixs) 14 | - 주요 변경 사항 (breaking changes) 15 | 변경 로그에서는 위의 3가지 내용을 사용합니다. 16 | 17 | 위의 3가지 목록들은 릴리즈를 수행할 때 관련 커밋에 대한 링크와 함께 스크립트로 생성할 수 있습니다. 18 | 물론 실제 릴리즈 전에 변경로그를 수정하고 배포할 수도 있습니다. 19 | 20 | 마지막 릴리즈 이후의 모든 제목 목록을 출력합니다. 21 | ※ 제목 (subject) : 커밋 메세지의 첫 번째 줄 22 | ```shell 23 | git log HEAD --pretty=format:%s 24 | ``` 25 | 26 | 해당 릴리스의 새로운 기능 27 | ```shell 28 | git log HEAD --grep feature 29 | ``` 30 | 31 | ## 중요하지 않은 커밋 식별 32 | - Formatting change(공백, 빈 줄 추가/제거, 들여쓰기) 33 | - 세미콜론 누락 34 | - 주석 35 | 등의 중요하지 않은 커밋의 경우 무시할 수 있습니다. 36 | 37 | git bisect을 통한 이진 탐색을 할 때 위와 같은 중요하지 않은 커밋은 무시할 수 있습니다. 38 | ```shell 39 | git bisect skip $(git rev-list --grep irrelevant HEAD) 40 | ``` 41 | 42 | ## 기록 조회 시 더 많은 정보 제공 43 | 다음과 같이 일종의 'Context'정보를 추가해야합니다. 44 | 45 | 다음 메시지들은 Angular 커밋에서 가져온 것입니다. 46 | - Fix small typo in docs widget (tutorial instructions) 47 | - Fix test for scenario.Application - should remove old iframe 48 | - docs - various doc fixes 49 | - docs - stripping extra new lines 50 | - Replaced double line break with single when text is fetched from Google 51 | - Added support for properties in documentation 52 | 53 | 모든 메시지들은 변경 사항이 있는 위치를 명시하려고 하지만 어떠한 규칙이 없는것 같습니다. 54 | 55 | 다음 메시지들을 보십시오 56 | - fix comment stripping 57 | - fixing broken links 58 | - Bit of refactoring 59 | - Check whether links do exist and throw exception 60 | - Fix sitemap include (to work on case sensitive linux) 61 | 62 | 해당 메시지들은 장소 지정을 놓치고 있어 어떠한 내용 변경이 있었는지 짐작할 수 없습니다. 63 | 물론 변경 내용을 일일이 찾아보면 찾아볼 수 있지만 이는 속도가 매우 느립니다. 64 | 65 | 그래서 커밋 메시지에 docs, docs-parser, compiler, scenario-runner, …와 같은 정보들을 저장해줘야합니다. 66 | 67 |
68 | 69 | # 커밋 메시지 형식 70 | ```shell 71 | (): 72 | 73 | 74 | 75 |