전체 보기
🚀

최종 테스트 준비

기출 오답노트

dto 안썼더니 모델이 뷰까지 가게 되어 오히려 코드 짜기 더 번거로웠다. dto 매핑 로직 익숙해져서 가서 금방 짜버리자.
설계 1시간 30분했더니 시간이 30분 부족했다. 45분부터 슬슬 컷해서 한시간내에 설계 무조건 끝내자
stream 썼다가, 카운트 잘못하는 일 발생했었다. 잘 보고 쓰거나 fot문 그냥 쓰자.
function 값 같이 컨트롤러에서만 쓸 enum은 그냥 하드코딩하자. 시간이 부족했었다. exception 메시지도 마찬가지다.
불안하겠지만, dto를 출력하는 건 마지막에 하자. 금방한다. 출력해야 할 거 확인해서 dto를 만들긴 하되, dto에 값 넣는 거 먼저 하자. enum까진 dto 안써도 괜찮은듯. 단, enum말고 다른필드도 동시에 필요하다면, 무조건 dto 사용하자.
리팩토링보다 기능들이 정상 동작하는 거 전부 확인 완료하는 게 먼저다. 중간, 중간 리팩토링하다가 시간이 부족했었다.
enum 끼리 관계 갖을 일 있다면 enum 넣어주자… string 말고.. string 넣었다가 메뉴가 아닌데 메뉴라 생각하고 find함수 돌려서 문제 생겼던 적 있다.
주석 일정부분은 그냥 달자. 안달면 오히려 고치는 게 더 오래걸린다. 변수명도 일단은 빠르게 짜야하기에 5초 이상 고민하지 말자.
설계 제대로 안하고 해봤더니 오히려 훨씬 오래 걸렸다. 설계 꼭 제대로 집중해서 하자.

12시에 도착해서 할 일

노트북 충전기 꽂고 받침대에 고정해두기
노트북에 메일 창, 네이버 영어사전, 노션 창, 내 깃헙 열어두기 (이미 열려있을거임)
폰 타이머 켜두기
프린트물, 공책, 볼펜, 음료 빼두기
시간 남는다면
크리스마스 실행시켜보기 (심적 안정 겸 java17 동작 확인)
중요해서 뽑아온 코드 읽기
너무 떨린다면 명심할 점 → 긴장될 땐 빨리 무언가에 몰입하자! 집중해버리면 긴장이 풀린다.
1.
요구사항을 생각하며 읽고 내 언어로 정리해두자. 물론 한나절 내내 읽으란 게 아니라, 처음에 내 언어로 정리해둬야 나중에 빠트린 거 확인할 때 편하다. 또, 요구사항에서 구조를 유추할 수 있다
2.
설계에 공들이자, 계속 고치는 대공사보다 설계에 공들이는게 더 빠르다
3.
ApplicationTest를 잘 살피고 가능해보인다면 여기 있는 것부터 만들자
4.
라이브러리는 알려준 그대로 쓰자! List를 shuffle 하라 했으면 그 모양 그대로
5.
너무 강박적으로 하지 말자 !! 쫄지 말자!!!!!!!!!!!!!!!!!!!!!!!! 할 수 있다
6.
잘 모르겠을 땐 엄청나게 빠르게 그림 그려보자
7.
다 풀 수 있겠단 생각 드는 순간 어려운 거 나오더라. 절대 그런 생각 하지 말자. 그냥 아무 생각도 하지 말고 문제에 몰입하자. 혹여나 쉽네..?란 생각이 들더라도 그 정도로 쉽게 나올린 없으니 뒤에 나올 내가 빼트린 무언갈 대비해 지금 하고 있는 거 최대한 빨리 끝내자.
8.
다 풀었다면, 리팩토링도 좋지만… 못생긴 코드는 무시하고, 일단 기능들이 다 제대로 동작하는지 확인하자. 특히 outputView쪽은 하드코딩한 건 없는지 확인하자
9.
푸는 도중에 못생긴 코드 일단 TODO 주석만 남겨두고 무시하자. 풀다가 리팩토링 금지
10.
테스트코드는 정말 쓰고 싶겠지만 일단 패스하자 시간 부족하다… 단순히 문법이 좀 헷갈리는 친구 있으면, 차라리 main에서 찍어보자. 나머진 집중력과 정신력으로 코드 작성하며 최대한 이해하기. 또, 커밋 넘길 때 아주 빠르게 스캔하고 넘기며 이해하기.
시간 내에 구현 하기 위해서 포기해도 되는 것 → 다 풀고서 리팩토링할 때 볼 것 순대로 정렬해둠
함수 역할, 15라인 신경 X
indent 깊이 신경 X
출력 시 개행 신경 X
상수X(하드코딩O)
enum 안 중요해 보이면 과감히 string으로 써버리고 나중에 대체하기
fucntion은 그냥 하드코딩하자. 대신에 dto는 포기하지 말기 (오히려 편함)
의존 관계 신경 X(지역변수O)
모델 적게 쓰고, 나중에 쪼개기
테스트코드 X
커밋메시지 괄호 신경 X

1시에 가장 먼저!!!

1.
프로젝트 생성하기
포크 방식
팀 깃허브 Fork 하기
내 깃허브 Clone 하기 → ChooSeoyoen 브랜치 만들기
템플릿 방식
팀 깃허브 use this template → create a new repository(java-christmas-6-ChooSeoyeon)
private → collaborator → add people → woowa-course 추가
내 깃허브 Clone 하기 → Main 브랜치 그대로 사용하기
2.
프로젝트 열어서 확인하기
깃헙 데스크탑에서 initial commit 보내지는지 확인
Application, ApplicationTest 부터 돌아가는지부터 확인
3.
Save Actions 적용하기, IntelliJ로 테스트 설정하기, setting이랑 project structure Java 17 확인하기
호오옥시 checkStyle 설정 안되어 있다면
woowadocs에 우테코 코드 포매터가 있다. 여기서 WootecoStyle 파일을 다운로드 받자.
Settings > Editor > Code Style > Java > 톱니바퀴 > Import Scheme > Intellij IDEA code style XML > 다운로드 해둔 WootecoStyle 파일 선택해 적용 > OK
Settings > Editor > Code Style > Enable EditorConfig support 설정 활성화
Settings > Tools > Actions on Save > Reformat code, Optimize imports 체크

문서 작업하기 (45분~1시간 안에 무조건 끝내기)

docs(README): 요구사항 분석
README
# 기능 구현 목록 ## Model ## Constant ## View ### InputView ### OutputView - [ ] 에러 메시지를 출력한다 ## Controller - [ ] 에러를 관리한다 - [ ] 실행한다 - [ ] 준비한다 - [ ] 시작한다 (입력 받는 거 기준으로 끊기) - [ ] 종료한다 # 부록 ## 기능 요구사항 분석 - - 예외 처리 ## 프로그래밍 요구사항 분석 - 공통 - 클린 : indent 2까지 허용, 3항 연산자 금지, 메서드는 15라인 이하로 한 가지 일, else 금지, switch/case 금지 - 에러 : 에러 메시지 출력 후 다시 입력 받기 - 테스트 : 도메인 로직(UI 제외)에 단위 테스트 구현, 기능 목록 동작을 테스트 코드로 확인 - 분리 : 핵심 로직과 UI 로직 분리, InputView/OutputView 구현 - 라이브러리 : Colsole.readLine() 사용 - 필수 테스트 - ## 메모 - 플로우 - 용어 - 관계 ## 스토리텔링식 설계 - 이야기 - 협력 : 요청과 응답 - 책임 : 하는 것(요청, 계산)과 아는 것 - 역할 : 책임의 집합(재사용성)
Java
복사
docs(README): 플로우 작성
docs(README): 기능 구현 목록 작성
예시

세팅하기

chore(package): 초기 패키지와 클래스 추가
model(enums), view, controller
feat(Controller): 에러 메시지를 관리한다
Controller
private final InputView inputView; private final OutputView outputView; public Controller(InputView inputView, OutputView outputView) { this.inputView = inputView; this.outputView = outputView; } public void run() { } private <T> T repeatUntilSuccessWithReturn(Supplier<T> supplier) { while (true) { try { return supplier.get(); } catch (IllegalArgumentException e) { outputView.printErrorMessage(e.getMessage()); } } } private void repeatUntilSuccess(Runnable action) { while (true) { try { action.run(); return; } catch (IllegalArgumentException e) { outputView.printErrorMessage(e.getMessage()); } } }
Java
복사
OutputView
public void printErrorMessage(String message) { System.out.println("[ERROR] " + message); }
Java
복사
Application
new Controller(new InputView(), new OutputView()).run();
Java
복사

작업하다 중간 중간 나올 코드

InputView → 왠만하면 parse(+validate), 너무 여러 단계로 쪼개서 parse해야하면 convert로 묶기
// 일반 public String readMoving() { System.out.println("입력해"); String inputMoving = Console.readLine(); validateInputMoving(inputMoving); return inputMoving; } // List<String> 인데 한 개 이상 무조건 입력 public List<String> readCarNames() { System.out.println("자동차 이름 입력해"); String inputCarNames = Console.readLine(); return convertInputCarNamesToList(inputCarNames); } private List<String> convertInputCarNamesToList(String inputCarNames) { List<String> carNames = Arrays.stream(inputCarNames.split(",")) .map(String::trim) .peek(this::validateCarNameNotEmpty) .toList(); validateCarNamesNotEmpty(carNames); return carNames; } private void validateCarNameNotEmpty(String carName) { if (carName.isEmpty()) { throw new IllegalArgumentException("자동차 이름은 앞뒤 공백을 제외한 1자 이상으로 입력해야 합니다."); } } private void validateCarNamesNotEmpty(List<String> carNames) { if (carNames.isEmpty()) { throw new IllegalArgumentException("자동차 이름을 하나 이상 입력해야 합니다."); } } // List<String> 인데 null 도 가능 -> https://github.com/ChooSeoyeon/java-menu/blob/ChooSeoyeon/src/main/java/menu/view/InputView.java public List<String> readMenusBy(String coachName) { System.out.println("\n" + coachName + "(이)가 못 먹는 메뉴를 입력해 주세요."); String inputMenus = Console.readLine(); return convertInputMenusToList(inputMenus); } private List<String> convertInputMenusToList(String inputMenus) { try { return Arrays.stream(inputMenus.split(",")) .collect(Collectors.toList()); } catch (Exception e) { throw new IllegalArgumentException("메뉴는 쉼표(,)로 구분해 입력해야 합니다."); } } // 정규식 (인데 왠만하면 안쓸거임) public static void validateMenu(String menu) { String regex = "([A-Za-z가-힣])+-\\d(,([A-Za-z가-힣])+-\\d+)*"; //문자-숫자 형식은 무조건 와야 하며 ,문자-숫자 형식은 올 수도 있고 안 올 수도 있다는 정규식 if (!Pattern.matches(regex, menu)) { throw new InvalidFormatException("[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요."); } }
Java
복사
outputview
public String formatPrice(int number) { return String.format("%,d", number) + "원"; } private static final DecimalFormat PRICE_FORMAT = new DecimalFormat("#,###'원'"); PRICE_FORMAT.format(1000);
Java
복사
dto → 매핑 (은 empty 만드는 거 말곤 그냥 모델에서 해버리자,,, dto에서 하면 좋지만 시간 X)
public record EventResult(GiftSummary gift, List<DiscountSummary> discounts, PaymentSummary payment) { public static EventResult createEmpty() { return new EventResult( GiftSummary.createEmpty(), Collections.emptyList(), PaymentSummary.createEmpty() ); } } public record PaymentSummary(int totalBenefitPrice, int finalPayment, String badgeName) { public static PaymentSummary createEmpty() { return new PaymentSummary(0, 0, BadgeEvent.defaultBadgeName()); } }
Java
복사
private static String formatGiftBenefit(GiftSummary gift) { if (gift.price() == 0) { return ""; } return Optional.of(gift) .map(g -> "\n증정 이벤트: -" + PRICE_FORMAT.format(g.price())) .orElse(""); } public String formatGift(GiftEvent gift) { if (gift == GiftEvent.NONE) { return "없음"; } return gift.getGiftMenu() + " " + gift.getQuantity() + "개"; }
Java
복사
모델 → equals
@Override public boolean equals(Object obj) { if (obj instanceof Registration) { Registration registration = (Registration) obj; return this.line.equals(registration.line); } return false; } @Override public int hashCode() { return line.hashCode(); }
Java
복사
모델 → crud
save(추가한다), update(수정한다), find(찾는다), delete(제거한다)
exists/check(존재하는지 확인한다), sum(더한다), generate(결과를 만든다), calculate(계산한다)
문법
private final Map<Day, String> weeklyMenus = new LinkedHashMap<>();
Java
복사

잘은 안 나오지만 나오면 당황하지 말자 코드

기능 입력 → 지하철
Test
컨벤션

제출

fork 방식
template 방식
지원 플랫폼 > 내 지원 현황 > ChooSeoyeon 이랑 비공개 저장소 주소소감 입력