[우아한테크코스] 웹 프론트앤드 6기 프리코스 🎰 3주차 미션 회고

이온·2023년 11월 8일
0

우테코

목록 보기
4/7
post-thumbnail

🎰 3주차 미션 : 로또

3주차 미션에 앞서

가장 먼저 2주차 공통 피드백을 최대한 반영하는 것이 중요하다고 생각해서 복기할 겸 정리해보았다.

[2주차 공통 피드백]

📍 readme
상세히 적고 계속해서 업데이트하기!
프로젝트에 대해, 어떤 기능을 담고있는지도 써보는 것이 좋다. 
마크다운 문법을 충분히 활용해보기.

📍 기능 목록(readme)
클래스 이름, 메서드 설계나 구현같은 상세한 내용은 처음부터 작성하지 않는다. 
왜냐하면 클래스 이름, 함수의 반환값은 언제든 변경될 수 있기 때문. 
구현해야 할 기능 목록을 정리하는데 집중하기! 
꾸준히 업데이트하는 것이 중요하다.

📍 예외적인 상황
기능 목록에 정리하고 기능을 구현하며 계속해서 추가해 나가자!

📍 구현 순서도 코딩컨벤션이다
클래스는 필드, 생성자, 메서드 순으로 작성한다.

📍 문자열, 숫자 등을 상수로 만들고 이름을 부여해 역할을 나타낸다.

📍 1 함수 1 기능
중복되는 코드는 함수 분리를 반드시 고민해보기
함수 하나는 15줄이 넘어가지 않도록 구현
함수 분리하는 연습을 충분히 하자!

📍 객체 만들기 학습
자바스크립트에서는 클래스 말고도 객체를 만드는 방법이 여러가지가 있다.

📍테스트를 작성하는 이유에 대해 경험을 토대로 정리해보자
테스트를 작성하는 과정은 
내 코드에 대한 빠른 피드백 뿐 아니라 학습 도구(JUnit학습)로도 사용 가능하다
이런 나의 경험을 통해 어떤 유용함을 느꼈는지 작성하기!!
또 테스트 코드는 작은 단위부터 시작하자!

또 계속 강조하는 말은 "요구 사항을 지키도록 노력하는 것이 가장 중요하다" 였다. 1차적으로 요구 사항을 모두 구현한 후, 다음으로 그 이상의 역량까지 녹여내는 단계로 가자고 다짐했다. 나같은 경우는 요구한 출력 문구가 정확히 무엇인지도 꼼꼼하게 읽어야 한다. 2주차때 사소한 오타 때문에 에러가 난 경험이 있었다. 😢 그런 실수를 방지하기 위해 예시 문구를 그대로 복사해서 가져왔다.

마지막으로 배운 것을 최대한 기록해서 증거로 남기는 것도 중요하다. 미션을 진행하며 새롭게 배운 부분은 주석으로 써가며 바로바로 이해해보고 그 다음 한번 더 코드를 보며 readme에 다시 정리를 하거나 블로그에 글을 남겨놓는 것도 좋을 것 같다. 마주한 에러들도 꾸준히 기록하자. 이러한 기록들이 나의 성장의 증거가 될 것이다!

1. 과제 요구사항 정리

프로그래밍 요구사항은 1,2주차와 동일

기능 요구사항

로또 게임 규칙에 따라 기능 구현
사용자 입력: 구입 금액(1000원 단위), 로또 번호, 보너스 번호
입력값으로 당첨 내역 및 수익률을 출력한 후 게임 종료
사용자가 잘못입력할 경우 에러 발생시킴 [ERROR]로 시작

추가된 요구 사항 정리

  • (2주차와 동일) indent depth는 2까지만 허용
  • 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다.
  • 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다.
  • else를 지양한다.(if 조건절에서 값을 return하는 방식으로 구현)
  • 도메인 로직에 단위 테스트를 구현해야 한다. 단, UI(Console 등)로직에 대한 단위 테스트는 제외한다.
  • 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다.
  • 제공된 Lotto 클래스를 활용해 구현해야 한다. (🚨#numbers 변경 불가, 필드 추가 불가❌)

2. 미션 진행의 흐름 (+ 각 과정 별 배운 부분 정리)

✅ 기능 명세서 작성

피드백대로 리드미를 좀 더 구체적으로 작성하면 좋을 것 같아서 노력해봤다.

구현할 기능 목록을 절차적으로 한번 소개 한 뒤, 이어서 기능 설계를 구체적으로 작성했다. 이는 코드 작업을 하는 내내 수정하며 죽은 문서가 아닌 나의 프로젝트를 제대로 설명할 수 있는 문서를 만들고자 했다.

구현할 기능 목록을 게임 플로우대로 한번 쭉 정리한 이유는 보기 좋게 화려히게 꾸미는 것보다는 요구사항을 꼼꼼하게 분석해서 로직을 구상하는 과정을 간결하게 드러내고 싶었다. 앞으로 더 복잡한 프로그래밍을 할 텐데 이렇게 나만의 분석 방법을 통해 이해도를 빠르게 올리는 연습도 많이 필요하다고 생각했다. 또 게임 절차를 먼저 고려한 뒤 게임에 대한 이해도를 완벽하게 쌓은 뒤 객체 지향적인 사고로 넘어가는 것도 큰 도움이 됐다.

(이런 식으로 작성)


또한 코드 작업을 하는 내내 자주 보기 위해 자주 실수하는 부분이나 습관을 들여야하는 부분을 아래에 메모했었다. 이 부분은 나중에 docs 부분에 따로 문서화해서 복습했으며 이 블로그 글을 쓸 때도 많이 참고했다.

✅ MVC 패턴의 적용 및 클래스 분리 연습

이번 피드백에서 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다라는 말이 있어서 이 부분은 MVC 패턴 적용을 통해 구현할 수 있다는 생각이 들었다. 따라서 2주차에서처럼 MVC 패턴을 적용했다. 핵심 로직은 model 부분으로 분리해 구현했고, UI를 담당하는 view를 분리해 입출력으로 사용자에게 보여지는 화면을 구현했다. 또한 controller에서 모든 프로그램의 흐름을 제어하는 형태로 완성했다.

첫번째 보다 익숙해진 느낌이 들었고 view, controller, model의 기능은 충분히 이해가 됐었다. 하지만 그 안에서 도메인 기능 부분 쪽이 고민됐다. 처음에는 '로또 추첨'에 대한 부분을 고민했을 때 로또머신에서 추첨을 할지 아니면 로또 객체 내에서 하나씩 추첨을 하는 메소드를 추가할지 등등 이런 자잘한 역할에 대한 고민들이 너무 많았다.

2주차의 피드백대로 클래스(객체)를 분리하는 연습을 중심으로 기능 설계를 하려고 노력했다. 머리 속으로 상상해보면서 "로또 용지를 뽑는 기계"가 있을 것이고 "로또를 파는 판매자"도 있을 것이고 "로또를 추첨하는 기계"도 있을 것이고 "로또" 자체도 있을 것이고 이런 식으로 객체를 주인공으로 어떤 식으로 서로 상호작용을 할지 생각했다. 각자의 역할을 확실하게 분리해주고 "판매자 객체" 안에서는 로또를 구매하는 로직을, "로또를 추첨하는 기계"에서는 로또를 추첨하는 로직을 부여하며 클래스 간 의존도를 최대한 낮추려 했다.

처음에는 어떤 흐름으로 데이터를 서로 주고받을지가 머릿속에 잘 떠오르지 않아서 아래와 같이 손으로 직접 흐름도를 그려보기도 했다. 흐름도를 내 손으로 직접 그리니 코드 작업을 하는 내내 머릿속에서 자연스럽게 이미지가 떠올라 어디에 어떤 것을 작성해야할지 판단이 빨랐다. 이러한 초반의 과정이 전체 작업 속도를 향상시켜주지 않았다 싶었다.

⬇️ 아직 부족한 첫번째로 그려본 흐름도 : 일단 구현할 기능이 뭔지 위주로 러프하게 작성해보았다.

⬇️ 두번째로 완벽하게 정리한 흐름도 : 객체 위주로 역할 분담을 다시 깔끔하게 시켜주었다.

✅ controller 부분에 전체적인 플로우 작성

controller 부분은 게임의 전체적인 흐름을 관장한다. 나는 컨트롤러가 입력-실행-출력에 대한 모든 것을 지휘하는 지휘자 느낌으로 생각했다. 실제 로직이 작성된다기 보다는 전체적인 흐름을 제어하고 기능 목록을 한눈에 볼 수 있도록 구성했다.

그래서 이 곳에서 어떤 식으로 코드를 만들것인지 아래 사진처럼 번호를 매겨서 순서대로 작성을 하고 구현을 완료하면 체크표시를 해가며 작업했다. 이렇게 여기서 먼저 게임의 흐름을 작성하고 "어떤 클래스에 어떤 역할을 하는 메소드가 필요하겠구나" 하는 생각이 들었고, 이 부분을 작업하며 전체적인 코드의 방향성을 잃지 않게 도와주었다고 생각한다.!

✅ 로또 게임에 대한 개요

손으로 작성한 흐름도 캡쳐본이나 위 사진에 잠깐 나와있듯, 이번 게임의 과정은 크게 "로또 구매 -> 로또 추첨" 이라고 생각했다. 2회의 입출력인 것이다. 그래서 세세한 클래스 분리 이전에 먼저 각 과정을 하나의 함수로 묶어서 흐름을 보기 좋게 나눠주었다. 1함수 1역할이라는 2주차 피드백 내용처럼 말이다! 그래서 구매는 buyLotto, 추첨은 drawLotto라는 함수를 만들어 컨트롤러의 start에서 하나씩 실행시켰다. 또 전체적인 작업의 순서 또한 "로또를 구매하는 로직"을 전부 끝내고 출력까지 확인 하고, 그 다음 "로또를 추첨하는 로직"을 전부 끝내고 출력을 확인하는 식으로 순차적으로 진행했다.

그 과정을 조금 더 상세하게 풀어보자.

1️⃣ 로또 구매

입력-실행-출력의 순서를 잘 떠올리며 진행했다.

1-1. 입력 : 사용자가 금액을 입력한다.

"인풋뷰에서 시용자가 입력한 금액을 받아와!"
(컨트롤러가 명령하는 말투를 상상ㅎㅎ!)

  • 가장 먼저 인풋을 숫자가 아닌지 한번 검증해주었다. 이후 그 입력값을 숫자로 타입을 변환해 Money 객체를 생성해줬다. 처음에는 객체로 만들 필요성을 못느끼고 그냥 number타입으로 썼는데 이후에 변경한 부분이다. number타입으로 쓰면 편하긴 하지만 나중에 사용자가 -1000과 같은 이상한 데이터를 넣어주게 되면 돈이 음수가 되고 이것은 유효한 데이터가 아니고 버그가 된다. 프로그램에서 돈같이 중요한 문제를 다룰 때에는 데이터가 이런 유효한 값이 아니게 되면 나중에 큰 문제가 될 수 있다. 그래서 Money 객체 내에 add와 suntract라는 함수를 메소드로 만들어 돈을 더하거나 차감하게 로직을 짰다. 여기서 Money 객체를 생성할 때 잔액이 0이 아니게 검증만 해주면 항상 유효한 데이터를 최대한 보장할 수 있다. 해당 부분은 프로젝트 레포 내 공부한 자료를 따로 작성해 두었다.

1-2. 실행 : 입력한 금액만큼 로또를 구매한다.

"LottoSeller의 buyManyLotto로 로또를 구매해!"

  • 금액을 바로 수량으로 계산해서 출력하는 것이 아니라 Money객체에 등록됐던 금액을 차감하는 방식으로 실제 나의 통장 잔고에서 빠져나가는 것처럼 구현했다. lottoGenerator가 준 하나의 로또를 구매해서 Lotto를 생성해 lotto 배열에 추가하고 금액을 차감하고, 또 하나 구매해서 추가하고 이런 과정을 잔액이 0이 될때까지 반복해서 전체 로또를 갖고있는 하나의 lottos 배열을 완성한다. 그리고 그것을 전체 로또를 만들어주는 Lottos객체에 보내준다. 이러한 '돈을 차감하고 로또까지 만들어주는 역할'을 LottoSeller안의 buyMany메소드로 추상화 했다.

1-3. 출력 : 구매한 로또들을 출력해서 사용자에게 보여준다.

"구매한 로또를 Dto로 변환해서 출력해!"

  • 이렇게 구매한 로또들을 객체 DTO로 담아서 반환하고 최종적으로 그것을 output view에 전달해준다. 여기서 전달받은 LottosDto의 배열의 길이로 로또의 수를 판단해 사용자가 몇개의 로또를 구매했는지 출력해주고, LottoDto안의 LottoDto를 돌며 각각의 Lotto를 출력하는 로직이다. 여기서 그냥 프린트해도 되지만 배열의 앞 뒤 공백을 제거하기 위해 하나의 함수를 더 거치게 구성했고 그 내용은 아래 트러블 슈팅에서 더 자세하게 다루고 있다.

로또 구매 완성! (아래 사진 참고)

2️⃣ 로또 추첨

입력-실행-출력의 순서를 잘 떠올리며 진행했다.

2-1. 입력 : 로또 머신을 작동시킨다.

"당첨 번호, 보너스 번호를 입력 받아서 그것을 토대로 로또머신 만들어서 작동시켜"

  • 가장 현실세계와는 달라서 이해하기 조금 어려웠던 부분인데 당첨 번호를 사용자가 직접 입력해 로또 머신을 새로 만든다는 개념이라서 조금 생소하게 다가왔다. 추첨은 기계가 하지만 그 당첨 번호를 만드는 것은 사용자이기 때문에 사용자의 "입력"으로 새로운 추첨 기계를 만든다는 생각으로 접근했다.
  • input view에서 당첨 번호와 보너스 번호를 각각 가져와서 검증까지 돌린 후 타입 변환까지 마친다. 또 그것을 inputLottoMachine이라는 함수에서 다시 받아서 로또 머신을 만든다.

2-2. 실행 : 구매한 로또들을 로또 머신에 넣어서 추첨을 돌린다.

"lottoMachine에 로또들을 넣어서 drawAll로 모두 추첨 돌려!"

  • 사용자의 입력값으로 만든 로또 머신을 실제 실행시키는 로직을 구현했다. 이 부분은 로또 추첨이라 lottoMachine의 역할로 판단해서 그 안에 drawAll,draw 메서드로 넣어주었다.
  • 보너스 번호가 있는지, 그리고 당첨 번호와 몇개나 일치하는지의 로직은 Lotto 클래스 안에서 처리해줬다. 로또의 데이터를 가져와서 여기서 사용해줘도 됐지만 로또 데이터의 응집성을 위해 로직 실행 장소를 바꿨다. 반대로 Lotto 클래스 내에서 당첨 번호와 보너스 번호를 받아와 거기서 추첨을 하는 식이 됐다.
  • 그렇게 개별 로또의 추첨 결과를 lottoMachine으로 가져와 그것이 로또 몇등인지, 상금이 얼마가 나오는지 등을 계산해주었다. 이 과정을 모든 로또에 해준 뒤 '추첨 결과를 출력하는 곳'에 전달해야하는데 이때 역시 DTO로 만들어 전달해주었다. (DrawResultDto 생성)

2-3. 출력 : 결과를 출력해 사용자에게 보여준다.

"추첨 결과를 통계 내서 출력해!"

  • DrawResultDto를 받아서 바로 해당되는 데이터만 찾아 Console.print에 템플릿 리터럴로 넣어서 출력해주었다. 이 부분에 대한 시행착오도 아래 트러블 슈팅에 따로 정리해 둔 부분이 있다.

로또 추첨 완성! (아래 사진 참고)

✅ 테스트 코드 작성(+에 대한 고찰)

일단 2주차 피드백 대로 중요한 비즈니스 로직을 처리하는 클래스 위주로 테스트 코드를 작성하게 되었다.

사실 테스트 코드는 현업에서 결함 없이 프로그램이 동작하는지 배포 전, 출시 전, 혹은 어떠한 협업 제출 전 확인하는 용도로 쓰인다고 알고있다. 에러를 미리 방지하고 나중에 프로그램의 유지 보수를 위해 필수적인 요소인 것이다.

현재는 단순한 과제이기에 그런 의도로 테스트 코드를 짜는 것은 당연히 아니지만 왜 우테코에서는 테스트 코드를 경험하도록 이런 과제를 만들었을까?

나의 개인적인 의견으로는 테스트 코드는 단순 점검 그 이상의 의미가 있다고 생각한다. 이번 미션에서 나는 테스트 코드를 짜며 '내가 어떤 코드를 작성하고 있는지' 다시 한번 정확하게 인지하게 됐고, 그래서 코드를 객관적으로 판단하게 되고 로직의 흐름에 대한 이해도가 더 올라갔다.

또 테스트 코드 작성을 통해 어떠한 예외처리가 더 필요할지 다양하게 고민하게 됐다. 개발자의 입장에서 프로그램을 만들 때보다, 사용자의 입장에서 이런 것을 입력하면?이라는 생각이 더 많이 떠올랐다. 요구사항의 기능적인 항목들을 차분하게 정리해주는 과정이었다고 생각한다.

또한 클래스 간 의존성을 낮추기 위해 한 노력들이 테스트 코드를 작성하며 빛을 발했다고 생각한다. 클래스 별 단위테스트를 구현할 때 클래스 간 복잡하게 연결되어있으면 테스트코드 작성도 더 복잡해지기 마련이다. 예를 들어 Lotto Seller에 대해서만 테스트를 하고싶은데 Lotto Seller에서 확인하고 싶은 부분이 lotto machine클래스에서 로직을 받아온다면 테스트 코드에서는 Lotto Machine 클래스도 고려를 해야하는 상황이 온다. 클래스 간 의존도를 최대한 낮추기 위해서 그러한 코드는 당연히 지양했었지만, 더 나아가 테스트 코드도 깔끔해진다는 장점이 있었다.

테스트 코드를 작성하는 경험을 통해 내 코드를 다듬는 것에도 큰 도움이 됐고, 초보자의 입장에서 나의 코드를 객관적으로 바라볼 수 있도록 도움도 받았던것 같다. 이것이 우테코의 의도가 아니었을까 생각한다.

(내가 만든 테스트 코드가 잘 돌아가고 성공하면 뿌듯하다 !)

3. 트러블 슈팅 및 기록해두고 싶은 과정

(1) 로또 목록 중 앞,뒤 공백 제거

요구사항 중 개행이나 공백 부분은 정말 신경 써서 고려해야한다.
사소하지만 이 때문에 테스트 통과가 안 될 가능성도 있기 때문이다!

예시 코드를 보면 배열 안 앞, 뒤에 공백이 없는데 내 출력에는 공백이 들어가 있었다. 그렇기에 lottoDto를 forEach로 돌며 숫자들을 가져오는 방법은 바꿔야했다.

아래는 이전 코드와 실행 결과로 다른 부분에 오타가 있지만 forEach만 주목해주세요

아래는 고친 코드와 실행 결과로 함수를 하나 더 만들어서 그 곳에서 배열 안의 숫자들을 join(', ') 쉼표+공백으로 join을 시켜 문자열로 만들어줬다. 그리고 그것을 다시 배열의 형태로 만들기 위해 대괄호로 묶어서 출력해주었다. 그리고 그런 작업을 하는 함수를 다시 printLottosDto라는 메인 출력함수에 호출시켜 로또 하나씩 넣어서 변환 시켜서 가져왔다. 조금 번거롭지만 요구사항의 예시와 공백까지 일치시키기 위한 노력이었다..!

(2) 당첨 번호를 문자열에서 숫자로 변경해야!

로직이 완성 된 후 에러가 나지 않았고 성공적으로 끝난듯 보였다. 테스트할 겸 일부러 로또와 3자리 수가 비슷한 숫자를 넣어서 당첨을 표시해봤는데 아래처럼 당첨 통계에서 당첨 번호가 전혀 비교가 안되는 것을 볼 수 있었다!! 너무너무 멘붕이었지만 콘솔을 여러번 찍어보고 이것저것 타입을 확인 해 본 결과 데이터 타입의 문제인 것을 확인할 수 있었다.

당첨 번호를 입력받을 때 나는 converter에서 각각의 숫자를 문자열로 저장했다. 근데 생성한 로또 번호들은 숫자이기 때문에 '1'과 1은 같은 번호라고 인식이 안되는 것이라 0개 일치로 결론난 것이었다. 따라서 그 아래 문자열 배열을 숫자 배열로 바꾸는 로직을 추가했다. 타입이 중요하다는 것을 다시한번 깨닫게 되는 소중한 에러 였다.

수익률 0%라고 에러고친 후 제대로 수익률 출력!

(3) 제공한 export의 형태를 되도록 유지

사실 나는 함수나 클래스를 가져올때 export class App {}으로 내보내는 스타일이다. 그런데 테스트에서 자꾸 아래 사진과 같은 오류가 떠서 의아했다. 도대체 무슨 뜻일지 계속해서 검색해본 결과 export의 형태 때문이라고 판단에 수정했더니 에러가 해결되었다.

제공받은 Lotto클래스나 App에는 class App으로 사용하고 마지막에 export default App로 내보내게 되어있었는데 그것을 내 식대로 수정한 것이 에러의 화근이었다.

이전에 코드리뷰에서 export의 형태를 통일시키면 좋겠다는 피드백을 받은 경험이 있었다. 그때는 그냥 '통일하면 보기 좋구나~'라고 생각하고 넘어갔었는데 이번 미션에서 이런 에러가 난 김에 두 export의 차이를 좀 찾아보게 된 것 같다.

name export와 export default의 차이라고 한다. (참고 링크)

  • export default

    export default class App 으로 사용, import시에 중괄호 작성이 필요없다.
    하나의 모듈에는 대개 하나의 export default가 존재한다.
    export한 이름과 상관없이 원하는 이름으로 import가 가능하다.

즉, default로 내보내면 어차피 해당 경로에서 받아오는 default모듈은 하나 뿐이니 {}안의 이름을 자유롭게 작성해도 되는 것이었다.

  • name export

    export class App으로 사용, import할 때 중괄호로 가져와야한다.
    모듈 하나에 여러 개체 존재 가능
    반드시 export한 이름으로만 import할 수 있다.

일단 겉으로 제공한 코드와 차이점이 없어야해서 생긴 에러이지만, 매번 익숙한 것만 사용하다가 이렇게 자세히 알고 넘어가게 되어 다행이라고 생각한다. 내보내기 방식을 통일할 때도 제대로 알고, 알맞은 방법으로 선택해서 코드를 작성하게 되었다.

(3) 테스트 코드의 expect() 괄호는 어디까지?

이 부분에서 오류가 나길래 나는 Money 타입에 대한 오류를 간과한 부분이 있나 생각하고 코드를 계속해서 다시 봤다. 왜 toBe함수를 쓸 수없다는 거지? 하며 "Money의 amount의 값이 3000 이기를 expect한거" 맞지 않나..하며 Money의 getter가 잘못됐는지도 한참 콘솔을 찍어보며 확인 했었다.

알고보니 expect()의 괄호 부분에 어디까지를 넣었는가에 따라 에러가 난 것이었다. expect(money.amount)를 작성하고 그 뒤에 .toBe()함수를 이어서 작성해야하는데 expect(money.amount.toBe())이렇게 이어서 작성 한 것이다.

이번 우테코에서 테스크 코드 작성을 처음 접해보았고, 과제를 제출해야하기 때문에 제한된 시간에 중요한 부분만 캐치해서 테스트 코드 짜는 방법을 배웠던 것 같다. 하지만 "expect()의 괄호 안에는 value를 집어 넣기!!"같은 기초적인 개념이 헷갈려서 에러를 마주하다니 조금 막막한 기분이 들었다. 앞으로 계속해서 테스트 코드를 짜야 할 순간을 마주할 텐데 이번 기회에 제대로 공부를 해야겠다는 생각이 들었다. (블로그 글로 작성해보기)

고치기 전고치고 난 후

(4) toBe vs toStrictEqual

임의로 로또 배열을 정해 Lotto객체를 만든 후 그것이 만들때 내가 넣은 배열과 같은것을 출력하는지 확인하려 테스트를 했다. 근데 오류가 났고 toBe 대신 toStrictEqual를 넣으라는 에러 해결 제시문도 출력됐다.

그래서 toStrictEqual를 넣었더니 에러가 아래처럼 해결이 됐고 나는 둘의 차이가 궁금해 찾아보았다. toBe는 같은 객체여야 한다는 것을 알게 되었다. 그러니까 새로 만든 "Lotto라는 객체"와 "그냥 배열"인 것과 비교하면 오류가 나는 시스템이었다. toBe는 그냥 같은 것을 비교하는 것인줄 알았는데 이런 에러를 통해 더 자세하게 비교할 수 있게 되었다.

(5) [타입 맞추기] Lotts에 넣어줄 때는 반드시 Lotto 객체로 만들어 넣어주기

코드를 길게 작성하기 번거롭다고 판단해서 아래처럼 new Lottos()안에 임의로 로또 세트들을 만들어서 바로 넣어주었다.

결론적으로 Lotto[] 객체가 들어가야하는 자리에 number[]타입을 넣은 것이라 당연한 에러이지만 그점을 간과했기 때문에 다시 실수하지 않기 위해 기록해본다.

시간이 걸리지만 JS Doc의 타입을 자세하게 작성한 것이 큰 도움이 되었다. Lotto[] 타입의 객체가 들어갈 자리라고 에러 메세지를 자세하게 말해주었기 때문에 나의 실수를 알아차릴수 있었다.

따라서 이렇게 Lotto 하나하나를 만들어 준 후 다시 그것을 Lottos안에 넣어주는 것으로 에러를 해결했다.

(6) 콘솔에 내가 한 들여쓰기가 보인다? (정규 표현식의 사용의 시행착오)

당첨 통계에 대한 아웃풋을 출력할 때 마주한 에러와 정규 표현식에 대해 고민한 것이 있기 때문에 기록해보려고 한다.

처음에는 굳이 다른 처리를 할 필요를 못느껴서 일단 아래 사진처럼 콘솔 프린트 부분에 당첨 통계 부분을 한꺼번에 기록하고 필요한 부분만 템플릿 리터럴로 가져왔다. 하지만 콘솔 창에 내가 들여쓰기한 부분이 그대로 드러나게 되는 결과를 마주했다. 이것은 요구사항과는 다른 출력이기에 수정이 필요했다.

두번째로 한 시도는 아래 사진처럼 그냥 들여쓰기를 순수하게 하나하나 없애보았다.

성공!

들여쓰기를 없애니 콘솔창에 공백 없이 깔끔하게 출력되는 것을 확인할 수있었다. 그런데 이렇게 작성하면 출력창은 제대로 뜨지만 코드 자체가 어색해보인다는 단점이 있었다. 다른 부분은 예쁘게 들여쓰기가 순차적으로 되어있어 코드가 깔끔해보였는데 이부분만 어색해보여서 개선이 필요하다고 생각했다.

여기서 나는 앞 부분 들여쓰기 공백이 콘솔 창에는 출력되지 않게 하기 위해 두 칸 이상의 공백은 지워주는 정규표현식을 아래와 같이 사용했다. 그런데 에러가 발생했다!! 😡 (⬇️)

String.prototype.replaceAll argument must not be a non-global regular expression이라는 에러를 여기서기 검색해보니 해답을 찾았다. 바로 ES12 문법의 replaceAll에 관련된 이유 때문이었다. 원래 자바스크립트에는 replaceAll 메서드가 없다가 생겼는데 이때 g flag를 항상 같이 사용해야 했다. g flag란 글로벌을 뜻하고 전역 검색, 문자열 전체에서 패턴을 검색한다는 뜻이다. 그러니까 문자열 내의 모든 값을 돌며 변환한다는 것이다. "모든 2칸 이상의 공백을 빈문자열로 치환해준다"라는 뜻이 된다.

따라서 g flag를 뜻하는 'g'를 마지막에 삽입해 아래와 같이 최종적으로 코드를 수정해주었으며 코드를 최종적으로 완성 시켰다.

결론적으로 코드가 보기 좋게 들여쓰기가 되어있고, 뒤에 정규표현식으로 처리를 해 주었더니 요구사항에 맞게 출력되는 것을 볼 수있다.

네번째 시도만에 만족스러운 코드를 작성한 것 같았다. 처음 내가 정규 표현식을 쓴 이유는 아주 간단한 몇 자 만으로 내 요구사항을 반영해 효율적인 코드를 짤 수 있다고 생각해서 였다. 또 정규 표현식 자체가 나에겐 아직 생소해서 가끔 알고리즘 문제 풀때 검색으로만 사용을 했었는데 이번 기회에 내가 만든 프로그램에 한번 더 사용을 하게 되면서 정규표현식에 대한 이해도를 높이고 더 익숙해지고 싶다는 목표도 있었다.

이렇게 나의 목표처럼 정규표현식을 사용하며 에러도 해결하고 새로운 것을 알게되는 경험을 했기 때문에 값진 에러라고 생각한다.

4. 종합적인 마무리 후기

이번 과제를 하며 다섯분들과 게더타운에서 스터디를 진행했다. 이전에 함께 공부했던 팀원분들인데 좋은 기회에 이곳 우테코에서 만나게 되어 다시 한번 스터디를 하게 되었다! 나 혼자만 프론트엔드이고 나머지 분들은 백엔드라서 처음에는 과연 함께 스터디를 하는게 의미가 있을까 생각했지만 정말 좋은 결정이었다!! 백, 프론트를 구분하지 않고 중요한 개념들에 대해 함께 토론하고 서로 공부하면 좋을 링크들을 공유하며 정말 많이 배웠던 것 같다. 또 백엔드 분들의 코드 소개를 들으며 객체 지향에 대해 더 많이 접할 수 있는 경험을 했던 것 같다.

혼자 공부하다보면 막막하거나 과연 잘 하고 있는지 의문이 들때도 있는데 온라인이지만 다같이 모여서 공부하니 정말 든든했고 의지도 많이 됐다. 마지막 4주차 미션때도 함께 밤 늦게까지 열정적으로 공부하며 마무리 할 계획이다. 다들 좋은 결과가 오길!

마지막으로 성공적인 제출! 😎✌🏻

이번 코드는 거의 1600줄 가까이 작성하게 되었다. 1주차, 2주차에 비해 계속해서 코드의 수가 늘어나고 있다. 나의 실력도 늘어나고 있다고 생각하고 싶다 ㅎㅎ

profile
👩🏻‍💻

0개의 댓글