본문 바로가기

개발 일기

230316 항해 1주차 회고

1주차 회고 - 자바스크립트 기본기 다지기

회고

실무에서 언제나 React, Next.js를 사용해 개발하지만, 바닐라 자바스크립트는 언제나 왠지 모르게 항상 뭔가 불편했었다. 처음 개발 공부를 시작했을 때 공부했던 것 이후로는, 바닐라 자바스크립트로 개발해본 경험이 없는 것이 사실이었다. 그 기본기가, 스스로 그 부족함을 알고있었기에, 첫 주차 과제부터 꽤나 자신감이 없이 시작했던 것 같다..

발제시간에 멘토님께서 자바스크립트 기본기 관련 주제에 대한 설명과 과제를 내어주시는데, 시작부터 좀 막막한느낌. 다 한번씩 공부했었던 개념이지만, 오랜시간 활용하지 않아서인지 낯설게 느껴졌다. 이럴줄 알고, 교육이 시작되기 전에 제공된 자바스크립트 강의를 한번 쭉 듣고 와서 그나마 다행이었지… 그래도 처음 공부할 때는 무슨 말인지 몰라서 여러번 보면서 겨우겨우 이해만하고 넘어갔던 개념들도, 다시 보면서 복기하니까 확실히 또 새롭게 알게되는 부분도 있고 알던것도 다시보였던것 같다. 매일 작성하는 자바스크립트 코드이지만, 어떻게 동작하고있는지에 대한 메커니즘은 생소하기도 했다. 이번 시간을 통해 오히려 몰랐던 부분을 조금이나마 채우고 성장할 수 있는 시간을 갖을 수 있었다.

자바스크립트 기본기가 중요한 이유를 설명해주시며, 기본기가 없는 개발자는 근본적인 문제를 진단하거나 해결하지 못하고 잘못된 솔루션을 그대로 사용하며, 내부에 폭탄을 심어둘 수 있다는 이야기가 좀 와 닿았다. 내가 작성하는 코드가 좋은 코드인지, 제대로된 방향으로 가고있는지에 대해 스스로 진단하는 힘을 기르려면, 좋은 코드를 많이 보는것도 있지만, 역시 기본기가 탄탄해야함을 다시 느꼈다.

조금 더 문제에 대해 정확히 바라보고 내가 생각해 볼 수 있는 여러가지 선택지들의 폭을 넓히고, 그 중 가장 좋은 방법을 찾을 수 있는 눈이 있어야 함을 느꼈다.

 

과제에서의 트러블슈팅

과제 1) 클래스 기반의 코드를 프로토타입 기반 코드로 변경하기

일단 클래스 기반의 코드도, 프로토타입도, 개념적으로만 알고있었고, 한번도 써본적 없는 개념이라, 직접 타이핑 하는 것 부터 어색했다. 사실 클래스를 자체적으로 만들어 쓰고 있지 않아, 어떤 상황에서 써야하는 개념인지 의문이 많이 생겼던 시간이었다. 나름 생각을 해보자면,

  • 객체지향적 프로그래밍이 필요할 때
    • 클래스는 함수와 다르게, 만들어둔 클래스를 가져와 확장해 쓸 수 있으므로, 재사용을 고려한 구조를 잡을 때 필요할 것 같다.
  • 변하지 않는 값이 고정적으로 들어갈 떄
    • api 호출에 대한 Fetch에서의 헤더, 바디 등 고정 옵션에 대한 정의?
    • GA 와 같은 Event tracker를 붙일 때?

와닿지는 않지만, 자바스크립트 자체가 “프로토타입 기반 객체지향 언어”라고 한다. 생성자함수와 프로토타입을 통해 상속을 구현할 수 있지만, ES6부터 도입된 클래스 덕분에 객체지향 프로그래밍을 훨신 더 간편히 구현할 수 있게 되었다고 함.

클래스로 한 눈에 보기 좋은 코드를, 직접 프로토타입 기반 코드로 변경하고 있으니, 클래스 기반 코드의 장점이 눈에 들어오기 시작했다.

JuniorEngineer.prototype = Object.create(Worker.prototype)
JuniorEngineer.prototype.constructor = JuniorEngineer

JuniorEngineer.prototype.**_super** = function(health){
	Worker.call(this, health);
};
  • 프로토타입 기반의 코드는, 클래스처럼 상속받는다는 느낌보다는, A가 할 일을 B에게로 넘기는 것같은 느낌.
  • 재사용기엔 답도 없어보이고 확실히 가독성도 좋지 않아보인다.

프로토타입 기반으로 클래스 기반 코드를 바꿔보며, 어떤 원리로 상속이 이루어지, 어떻게 구조가 확장되는지에 대한 것을 직접 느낄 수 있었던 부분이 도움이 됐다.

요구사항이 추가되면, 특정 기능을 재사용 해야할 경우도 있게되는 등, 현재 요구사항에 맞게 최적화된 구조를 고민해야할 경우가 많다. 클래스를 이용해 확장 가능한 경우의 수를 염두해두고 설계해나가면 확실히 더 구조화된 설계가 가능하겠다는 생각을 했다.

 

과제 2) 고비용 작업으로 인해 발생하는 프레임 드랍 최적화하기

자바스크립트의 비동기 작업에 대한 과제다. 사실 비동기적인 작업을 하는 코드는 api를 호출하거나 할 때, 자주 사용하던 코드이기에, 조금은 익숙할 줄 알았는데, 그건 아니었다. 그냥 대부분 모르고 있었다고 해도 과언이 아니겠다. 새롭게 알게된 것을 정리해보자면,,,

  • 자바스크립트의 동시성. 기본적으로 자바스크립트는 단일스레드 언어라 한번에 하나만 처리 가능. 자바스크립트를 실행하는 콜 스택(Call Stack)은 싱글 스레드지만, 서버에게 리소스를 요청하거나 파일 입출력 혹은 타이머 대기 작업을 실행하는 Web APIs 들은 멀티 스레드이기 때문에 동시 작업 처리가 가능
  • 이벤트 루프 동작 과정. 비동기 함수 작업을 Web API에 옮기는 역할을 하고 작업이 완료되면 콜백을 큐에 적재했다가 다시 자바스크립트 엔진에 적재해 수행시키는 일종의 '작업을 옮기는 역할' 만을 함.
    • 작업을 처리하는 주체는 자바스크립트 엔진과 웹 API
    • 이벤트 루프는 Call Stack에 현재 실행 중인 작업이 있는지 그리고 Task Queue에 대기 중인 작업이 있는지 반복적으로 확인하는 무한 루프만을 돌고, 대기 작업이 있다면 작업을 옮겨주는 형태로 동작
  • 그냥 비동기가 다 똑같은 비동기인줄 알았는데… Micro Task, Macro Task, Animation Frame….?
    • Micro Task → Animation Frame → Macro Task 순서대로 실행

과제는 사실, 단순히 무거운 작업을, Web api로 보내 비동기적으로만 처리하면 된다고 생각했다. 뭔가 화면상에서 확인할 때는 해결한 줄 알았는데, 아니었던 것 같음.

 

for (let i = 0; i < this._tasks.length; i++) {
  setTimeout(() => {
    this._tasks[i]()
  }, 0)
}

이렇게했을 떄 생길 수 있는 문제점….

1. 순서 보장 문제

**setTimeout**은 비동기적으로 작업을 큐에 넣기 때문에, 작업의 순서가 보장되지 않는다. for 루프 내에서 **setTimeout**을 사용하여 작업을 큐에 넣으면, 모든 작업이 거의 동시에 실행될 가능성이 있다는 것. 작업의 순서가 중요한 경우엔 확실히 문제가 된다.

2. 비효율성

**setTimeout**을 사용하여 각 작업을 비동기식으로 실행하면 기본적으로 '0'밀리초의 최소 지연 후에 각 작업이 매크로 작업으로 실행되도록 예약하는 것. 이는 곧, 불필요한 매크로 작업이 생성되고 잠재적으로 이벤트 루프에 불필요한 마이크로 작업이 많이 생성된다는 의미.

3. 추가적인 비용 발생

**setTimeout**을 사용하여 작업을 큐에 넣으면, 매번 타이머를 생성하는 비용이 추가적으로 발생합니다. 이로 인해 성능이 저하될 수 있습니다.

 

 

do() {
    const taskBundleSize = 100
    const taskBundleCount = Math.ceil(this._tasks.length / taskBundleSize)

    // 비동기로 여러 작업을 분할한다음 순서를 보장하기 위해서
    // Promise chain을 사용
    let taskChain = Promise.resolve(0)
    for (let i = 0; i < taskBundleCount; i++) {
      	taskChain = taskChain.then((next) => this._do(next, next + taskBundleSize))
    }
}

_do(start, end) {
    const tasks = this._tasks.slice(start, end)

    for (let i = 0; i < tasks.length; i++) {
    	tasks[i]()
    }

    // 비동기로 작업을 분할하고 순서를 보장한다고 Promise만 사용한다면
    // 우선순위가 높은 microTaskQueue를 계속 점유하기 때문에 병목이 해결되지 않음.
    // setTimeout을 통해 중간에 macroQueue로 작업을 한번 빼줘야 함.
    return new Promise((resolve) => {
      	setTimeout(() => resolve(end), 0)
    })
}

1. 작업 분할

작업을 분할하여 순차적으로 실행하므로, 전체 작업이 동기적으로 실행되는 것보다 더 효율적

2. 작업 분할

**Promise**와 **then()**을 사용하여 작업을 순차적으로 실행하므로, 작업의 순서를 보장할 수 있다.

결론적으로, 작업을 분할하여 순차적으로 실행하면서, 불필요한 대기 시간을 최소화하여 리소스를 효율적으로 사용할 수 있음.

 

과제 3) V8엔진에 대해 이해한 내용을 바탕으로 A에서 작성한 코드의 성능을 개선하기

새롭게 알게된 사실?

  • 자바스크립트는 동적 타입 언어로, 변수가 어떤 타입의 데이터를 저장하고 있는지를 프로그램 코드 상에서 명시적으로 선언하지 않기에, 값의 타입을 기반으로 변수 타입이 동적으로 결정된다. 그래서 객체의 프로퍼티에 접근하는 속도면에서 정적 언어와 차이가 남.
  • 그래서 프로퍼티를 저장하기 위해 V8 엔진은 ‘히든클래스’라는 것을 사용함.
    • 객체에 새로운 프로퍼티 추가할 떄 히든클래스를 생성하고, 히든클래스 프로퍼티의 정적인 위치를 저장해서 실제 데이터가 저장되어 이는 위치에 대한 포인터를 제공.
    • 객체의 obejct 구조(모양) 을 따로 저장하고 이 “모양” 에다가 객체의 모든 프로퍼티 이름과 그에 대한 속성 정보를 저장
    • 즉 객체의 구조(모양)를 기억해 위치를 저장하고 그 위치로 값을 찾아내는 것. 같은 모양의 객체들은 같은 히든클래스를 참조하는 것.

과제 트러블슈팅

  • 단순히 이 히든클래스라는 개념에 대해서 이해하지못해, 몇번을 다시 문서를 읽었던 것 같다.
  • 개념을 알고난 후에는, 객체의 동적 속성 추가나 일관되지 않은 개체 모양과 같은 패턴같은 것들을 찾아, 그러한 것들을 최대한 일관되게 만들어줬다.
    • 값이 조건부 생성되는 것 → 무조건적으로 생성하도록
    • 다른 키값 삭제 등
  • 히든클래스의 작동 원리와 JavaScript 최적화에 있어서 히든클래스의 중요성에 대해 더 잘 이해하게 된 것 같다.
  • 성능에 영향을 미칠 수 있는 코드 패턴을 인식하는 방법과 더 나은 효율성을 위해 리팩터링하는 새로운 방법을 배움.

 

공개 Q&A

  1. 주니어의 성장방법?
    • 블로그(기록하는 습관 - 생각이 담긴)
    • 자기만에 몰입할 수 있는 환경을 찾자
    • 모르는것 인지했으면 꼭 이해하고 넘어가자
  2. 지식을 습득하는 방법?
    • 공식문서 위주로 튜토리얼 학습
    • 모르는 것을 스스로 인덱싱 해두자
  3. 리팩토링시 코드 개선하는 기준?
    • 요구사항 추가 수정했을때 얼마나 빠르게 대응이 가능한가
    • 잘 작성된 코드는, 발생할 수 있는 상황에 대응이 빨라야 함.
      • 데이터 형식 변화, 배포환경 변화 등등
    • 작성 후에 다시 돌아봤을때도 이해하기 쉬워야함
    • 테스트코드를 작성하진 않더라도 테스트가 되는지 판단하는 것
  4. 클래스 사용?
    • 객체지향적으로 장점
    • 왜 나왔는지?
  5. 사수가 없는 환경?
    • 사수가 없는 환경에 익숙하게끔 성장
      • 오픈소스?
      • 유데미 인강
  6. 인공지능 활용?
    • type doc
    • test code
    • 모르는 것에 개념
  7. 주니어가 가지면 좋은 역량
    • 1인분한다는것을 보여줘야함?
    • 성능개선 - 속도개선? 트래픽 개선? 유저 이탈 감소?
    • 비즈니스적 지표 개선한거 보여주기
    • 리딩능력?
    • 개발 = 문제해결의 연속. 개발로 우리는 일할 뿐, 꼭 코드일 필요 없다. 문제 해결을 잘하는게 중요
      • 문제해결의 범위? 회사를 리팩토링 - 업무방식, 툴 개선도 ㅇㅋ, 안좋은 상황을 개선하면 됨
      • 문제 인지 - 어떻게 해결할지 고민하는 자세
      • 커뮤니케이션
      • 코드적으로는 성장할 방법이 많음.

 

1주차를 마무리하며

감사했던 점

  1. 좋은 배움의 터에 온 것에 감사
    1. 주니어로서 성장하기에 더없이 좋은 곳이 아닐까
  2. 나와 같은 열정의 온도를 가진 사람들을 만나, 고민을 나누고 함께 공부할 수 있다는 것에 감사
    1. 렛츠밍글
    2. 즐거웠던 회식
    3. 여기에 있는 사람들이랑 모두 친해지기. 목표!
  3. 좋은 멘토님들을 만난 것에 감사. 아직 내가 무엇을 물어야할지, 뭘 모르는지도 잘 판단이 안되는 주니어지만, 뭐라도 옆에서 하시는 말씀들 그냥 주어담다보면, 괜히 조금이라도 성장할 수 있을것 같은 기분.

아쉬운 점

  1. 현업과의 병행 속 피로. 깊게 고민할 시간 부족. 아무래도 시간이 날 때에 하는게 아니라 시간을 내서 어떻게든 해내자는 마음가짐 필요함을 느낌
  2. 멘토링 시간에 대한 준비를 많이 해가지 못한 것이 아쉽다.
  3. 모르는 것을 드러내는 것에 대한 용기가 아직 많이 부족한 듯 하다. 다들 주변에 나보다 연차가 있으신 분들의 경험이나 생각들의 깊이가 깊다는 것을 느끼고 배울점이 많다는 것이 보인다. 그에비해 내가 모르는 것이나 가지고 있는 고민들이 드러내기에 부끄럽다는 생각을 많이 하는 듯. 어차피 다 잘하는게 아니라, 나같은 사람도 분명 있을텐데.
    1. 모르것에 있어서 부끄러워하지말고, 하나라도 더 묻고 더 배우려는 자세로 임해야겠다!