본문 바로가기

Retrospect

우아한테크코스 3기 프리코스 2주차 후기

 

역시나 수요일 3시 미션 안내 메일이 도착했다.

2주차 안내 메일을 받았다면 1주차 미션이 정상적으로 제출된 것이라고 말씀해주셔서 마음이 놓였다.

 

 1주차 미션    2020. 11. 25. (수) ~ 12. 01. (화)
 2주차 미션    2020. 12. 02. (수) ~ 12. 08. (화)
 3주차 미션    2020. 12. 09. (수) ~ 12. 16. (수)
 최종 코딩테스트 2020. 12. 19. (토)
 최종 합격자발표 2020. 12. 30. (수)

 

 


미션 내용

[1] 기능 요구사항

- 자동차경주 구현

[2] 프로그래밍 요구사항

- alert 메서드 사용

- depth < 3, 함수 간결화 (1함수 1기능), 코드 컨벤션 적용

- 함수길이 < 15줄

- 각 요소에 지정된 id값 부여

- Car 객체 작성

- var 사용(X)

- import로 스크립트 모듈화

- 템플릿 리터럴로 가독성 개선

[3] 미션진행 요구사항

- README.md에 기능목록 작성

- commit 단위는 기능목록 단위로 추가

 

제출방법 : 다음 주 화요일 23시 59분까지 Github제출 + 메일 발송

 


1주차 피드백 요약

[01]  이름을 통해 의도를 드러내고, 축약하지 않는다.

[02]  linter와 code foratter의 기능을 활용한다.

[03]  불필요하게 공백라인을 만들지 않는다.

[04]  space도 convention이며, space vs tab을 혼용하지 않는다.

[05]  구현순서도 convention이다.

[06]  최대한 중복을 없애고 컴포넌트화하여 재사용한다.

[07]  의미없는 주석을 달지 않는다.

[08]  var를 사용하지 않는다.

[09]  commit 메세지를 의미있게 작성한다.

[10]  기능목록은 구현하면서 계속 업데이트 한다.

[11]  기능목록을 너무 상세하게 작성하지 않는다.

[12]  기능목록에 예외적인 상황도 정리한다.

[13]  마크다운 문법을 학습해보고 적용해본다.

 

 

 


후기 & 자체 피드백

일주일이라는 비교적 짧은 호흡으로 과제를 밀도 있게 진행하고, 또 새로운 과제를 시작해서 리프레시도 할 수 있데다가 과제 마감 바로 다음날 그 과제에 대해 피드백을 받을 수 있다니 프리코스 참가 만족도가 최고조에 달했다...

 

의외로 DOM 요소를 '선택'해서 변수에 담는 부분에 시간을 많이 쏟았다. DOM 요소를 수정하는 것뿐만 아니라, 접근하는 것도 크게 성능을 저하(참고자료)시킨다고 해서, 나는 상수를 모아두는 config 모듈에서 필요한 요소를 최초 한 번씩만 접근해서 변수에 담고 각각 export 해서 사용했었다. 그리고 이 모듈 저 모듈에서 import 해서 그대로 사용하다 보니 그제야 전역 변수와 다를 게 없다는 생각이 들었다. 전역 변수를 지양한다는 원칙에 따라, 요소를 import 해서 사용하지 않고 그때그때 지역변수에 담아 사용하도록 수정했다.

 

그렇게 고치고 났더니 이번에는 리로드 했을 때 첫 화면을 띄워주는 속도가 눈에 띄게 느려졌다. 그래서 다시 어떻게 하면 전역 변수를 사용하지 않으면서 요소 접근을 최소화할 수 있을까 고민하게 되었다. 동시에, 필요한 요소를 미리 예상해서 모조리 선택해 들고 다니는 것보다 필요할 때 바로바로 선택해서 쓰는 게 효율적이지 않은가 하는 의문이 들었다. 특히 나 말고 다른 사람이 내 코드를 수정한다고 가정한다면, 그게 더 자연스럽게 느껴졌다.

 

절충안으로, 한 함수에서 연관된 함수 포함 여러 번 사용될 경우에는 매번 DOM에 접근하지 않고, 최초 한 번만 지역변수에 담아서 매개변수로 전해주는 방식을 택했다. 아직 뚜렷한 답을 찾지 못해서 다른 분들의 PR도 봐보면서 다음 주차까지 계속 고민해보려고 한다.

 

첫째, 기능목록을 너무 상세하게 작성하지는 않았는가?

1주차 피드백 덕분에 기능목록을 잘못 작성하고 있었다는 점을 깨달았다. 나는 언제든지 변경될 수 있는 메서드 이름을 구구절절하게 나열했었다. 

 

이번에는 지나치게 디테일한 부분은 적지 않도록 노력하고 굵직굵직하게 구현해야 할 기능 위주로 목록을 작성하는데 집중했다. 가장 처음 작성할 때 떠오르는 예외상황을 우선 적어두고, 실제 구현하면서 새로 발견한 예외상황들은 문서에 계속 추가해가며 업데이트했다. 구현을 마치고 구현한 코드와 내용과 흐름과 일치하는지 확인하기 위해 다시 한번 기능목록을 읽어보았다. 피드백을 반영해서 작성한 2주 차 기능목록이, 1주차에 작성한 것보다 기능과 흐름 파악에 훨씬 도움이 되는 것 같았다.

(왼쪽) 1주차 구현 기능 목록 일부               (오른쪽) 2주차 구현 기능 목록 일부     

 

둘째, 함수당 15줄을 넘지 않으며 1함수 1기능으로 분리했는가?

15줄 조건이 추가된 덕분에, 기능 분리를 조금 더 잘할 수 있었던 것 같다.

 

1주차 과제를 수행하면서 '1기능'은 구체적으로 어느 정도 크기로 설정해야 할까 하는 의문이 있었다. 예를 들어, '숫자 야구게임 실행'을 하나의 기능이라고 정의할 수 있다면 100줄이 넘는 코드가 하나의 함수에 들어가게 될 수도 있고, '인풋이 숫자인지 확인'을 하나의 기능이라고 정의할 수 있다면 코드의 길이가 10줄 안쪽으로 해결될 것이다. '기능 단위'로 생각하고 접근하는 것이 낯설었기에 이렇게 '1기능'이라는 표현에 대해 감을 잡지 못하고 있었다.

 

따라서 이번 미션에 주어진 15줄 제한 조건은 '1기능'이 대략 어느 정도 단위인지 감을 잡는데 아주 좋은 지표가 되었다. 물론 15줄이 넘지 않는다고 무조건 하나의 기능이 담긴 것이라고 할 수는 없겠지만 나와 같은 초심자에게 어느정도 의지할 수 있는 고마운 가이드라인이 되었다.

 

셋째, 스크립트를 모듈화는 어떤 기준으로 했는가? 

1주차의 목표가'함수를 분리'하는 것이었다면, 이번 주차의 목표는'모듈을 분리'하는 것이라고 명확하게 제시해주셨다. 함수 분리의 기준이 기능이라면, 모듈 분리의 기준은 무엇일까? 하는 의문이 생겼다.

 

우선, 모듈을 분리하는 이유는 무엇일까? 100쪽이 넘지 않는 책에도 목차가 있기 마련이다. 연관된 내용끼리 묶어놔야 독자가 원하는 내용을 찾아 읽기 수월할 것이다. 모듈을 분리하는 이유도 비슷한 것일 거라고 추정해본다.

 

한편, 모듈을 분리한다면 코드 작성자 및 이후 수정하는 사람 모두 다른 파일로 이동해서 보아야 한다. 반대로 같은 모듈 내에 있다면 휠을 위아래로만 움직여 인접한 함수끼리 한 번에 모아볼 수 있을 것이다. 코드의 흐름상 모아 보는 것이 가독성에 도움이 되는 함수들이라면 같은 모듈에, 반대로 흐름상 주요한 코드가 아니라 당장 보지 않아도 전체 흐름이 보인다면 해당 코드를 다른 모듈에 보관해도 될 것이다.

 

「실용주의 프로그래머」 에서는 직교 성(Orthogonality)이라는 개념을 소개한다. "하나가 바뀌어도 나머지에 어떤 영향도 주지 않으면 서로 직교한다고 할 수 있다."는 이 개념은 독립성(Independence) 또는 결합도 줄이기(Decoupling)으로도 말할 수 있다. 이렇게 직교적으로 시스템을 작성하면 "어떤 개발에도 내재하는 리스크들을 감소시켜준다. 감염된 코드는 격리된다. 어떤 모듈이 병에 걸렸다 해도 시스템의 나머지 부분으로 증상이 전파될 확률이 낮다. 게다가 그 부분만 도려내고 새롭고 건강한 놈으로 이식해 넣기도 쉽다."는 장점을 가지고 있다.

 

그 외에 "각 모듈은 다른 부분과 독립적인 기능을 구현해야 한다.", "직교적인 설계를 테스트하는 손쉬운 방법이 있다. 컴포넌트들을 나누었을 때 다음과 같이 스스로에게 물어보라. '특정 기능에 대한 요구사항을 극적으로 변경했을 경우, 몇 개의 모듈이 영향을 받는가?' 직교적인 시스템에서는 답이 '하나'여야 한다.", "현재 코딩하는 부분뿐만 아니라 애플리케이션의 큰 맥락을 끊임없이 살피지 않으면 의도하지는 않았겠지만 다른 모듈에 중복 기능을 추가하거나 동일한 지식을 두 번 표현할 수도 있게 된다."와 같은 설명을 통해서 모듈 분리에 대해 대략적인 기준을 잡을 수 있었다.

 

 

 


배운 내용 정리

 

querySelector vs getElementById

둘을 비교한 글은 많다.

querySelector()가 더 느리니까 사용하지 말라는 의견도 있고, 큰 차이 없으니까 사용해도 된다는 의견도 있다.

getElementById면 id만 조사하면 되는데 비해 querySelector는 어떤 태그인지부터 파악해야하니까 할일이 더 많겠다.

하지만 많이 쓸수록 느려지는 것을 이미 경험해버려서 적게쓰고 싶다..

 

[강의 4-11] querySelector()에 성능문제에 대해 질문 드립니다.

getElementById와 querySelector()의 성능 차이 때문에 주변에서 querySelector를 사용하지 말라고 하는데 정말 그런 건지 궁금합니다.

hashcode.co.kr

 

 

JavaScript Selector Performance

One of the students in my Vanilla JS Slack channel asked me about the performance difference between querySelector() and things like getElementById() and getElementsByClassName(). Specifically, getElementById() and getElementsByClassName() are more than tw

gomakethings.com

 

커밋 메세지 변경 방법

git rebase -i HEAD~3
바꾸고자하는 커밋의 'pick'을 edit로 변경 후 저장(wq)
git commit --amend 
git rebase --continue

 

 

Git Commit Message 바꾸는 방법

Git을 사용하다 보면 커밋 메세지에 오타가 나거나 조금 더 나은 메세지 내용으로 바꿔야 할 때가 있습니다. 일반적으로 그대로 두는 것이 제일 좋지만 불가피하게 바꿔야 한다면 어떻게 해야 할

tech.javacafe.io

 

HTML 문서 수정하기

[1] 해당 노드에 바로 적용하는 방법

  ol.before('before'); // <ol> 앞에 문자열 'before'를 삽입함
  ol.after('after'); // <ol> 뒤에 문자열 'after를 삽입함

  let liFirst = document.createElement('li');
  liFirst.innerHTML = 'prepend';
  ol.prepend(liFirst); // <ol>의 첫 항목으로 liFirst를 삽입함

  let liLast = document.createElement('li');
  liLast.innerHTML = 'append';
  ol.append(liLast); // <ol>의 마지막 항목으로 liLast를 삽입함

 

[2] 인접한 노드에 적용하는 방법

div.insertAdjacentHTML('beforebegin', '<p>안녕하세요.</p>');
div.insertAdjacentHTML('afterend', '<p>안녕히 가세요.</p>');

(왼쪽) 해당 노드에 바로 적용               (오른쪽) 인접노드에 적용

 

 

문서 수정하기

 

ko.javascript.info