공부하는 블로그

코드스피츠77 - ES6+ 기초편 1강 본문

코드스피츠 정리

코드스피츠77 - ES6+ 기초편 1강

devtimothy 2018. 10. 7. 22:51

코드스피츠77 - ES6+ 기초편 1강

해당 글은 코드스피츠 S77 1강을 보고 정리한 내용입니다. 영상으로 공부하시는 분들 도움이 되시면 좋겠습니다. (_ _)

개발 기본: 너 대체 왜 그랬어?

코드를 어떻게 짰을까?를 어떻게 설명할 것인가? 각자 생각이 다른데, 정답은 없고 취향만 있는 걸까? 아니면 큰 기업의 코딩 컨벤션을 따라야 하는 걸까?

실무 지식, 체계 등을 먼저 배우는 경우가 많다. 그러나 지식은 언젠가는 변화하기 마련. 안드로이드도 자바가 아닌 코틀린으로 넘어가듯...

지식에만 휩쓸려서 앵귤러가 최고야, 자바가 최고야! 하게 되는 경우가 있다. 언어나 지식에 휩쓸리지 않는 철학적 기반을 마련하라.

철학

서양인들이 생각하는 근대 주류 철학 기조의 두가지. 합리주의와 상대주의가 프로그래밍 세계에도 반영되어 있다. 자식클래스가 영원히 자식클래스가 아니듯... JVM 입장에서 윈도우는 플랫폼. 자바 입장에서 JVM이 플랫폼. 하나로 정의하고 불변했으면 좋겠지만 상대주의적 관점으로 바라보지 않으면 안 된다. 그러나 상대주의의 관점. 윤섭이는 뚱뚱하다는 어떻게 결정하나? 기준이 필요하다. 이때 합리주의가 필요하다. 상대주의와 대립되는 것은 합리주의가 아닌 절대주의다.

가치, 원칙, 패턴 (구현 패턴)
  1. 가치: 집단, 사회, 회사, 팀, 조가 공통으로 인식할 수 있는 가치. 가치는 소속된 집단 별로 다중적으로 나타난다.

    1. 의사소통: 너 왜 이렇게 짰어?

    2. 단순함: 복잡해서 유지보수 힘들어서요

    3. 유연함: 그 전 함수는 하나밖에 못해서 레이어 나눠서 다양한 케이스에 대응할 수 있게 했어요!

  2. 원칙

    • 예시: 교장선생님 훈화 말씀. 뙤약볕 밑에 우리가 서있고, 훈화말씀이 시작된다. 왜 근데 학생들은 줄맞춰 서있냐? 가치, 원칙이 왜 있는지 이해 못하면 뻘짓이라고 생각한다.

    • 학생 하나가 쓰러져있다. 근데 모두 원칙을 지킨다면 쓰러진 사람을 보고 사고가 발생했음을 즉시 알수 있게 된다. 모두가 원칙을 지키고, 그대로 돌면 깨뜨린 것에 대해서는 바로 알 수 있다.

    • 다들 원칙을 지키지 않는다면? 쓰러진 사람을 보고 아파서 그런지, 그냥 누웠는지 알 방법이 없다. 원칙을 정하면 원칙의 예외를 정해놓는다면 그 방법을 즉시 알 수 있다.

    • 중요한 것만 원칙을 지켜야 한다. 가치보다 원칙을 정할 땐 더 신중해야 한다.

    1. 지역화: 전역변수 아닌 지역변수. 전체 영향보다는 지역화 할 수 있도록 한다.

    2. 중복 제거: 똑같은 반복해서 나오지 않게 해!

    3. 대칭성: 인간은 get 있으면 set 있을거 같다. 대칭성에 대한 뇌의 본능적인 작용이 있다. 쌍을 맞춰 인터페이스를 맞춰라. 문 열었는데 못나올거란 생각 안하듯이 말이다.

  3. 패턴

    • 선배들의 조언. (디버깅 비용은 컴퓨터 프로그래밍 역사상 줄어든 적이 없다. 선배들의 조언이 분명 효율적이라는 것.)

    • 개발론: 함수형, 객체지향형, 테스트 주도 개발 등... 해보니 좋더라.

    • 설계론

    • 각종 적용 패턴

  1. 동기

    1. 시간

프로그래밍 & 타이밍

  • Language code

    • Lint time: 컴파일 전 예상 에러를 잡아냄.

  • Machine Language: 기계가 읽을수 있게 번역됨. 컴파일러의 개입.

    • Compile time

  • File: 자바는 class 파일, C는 binary 파일이 만들어짐

  • Load: 클릭하면 메모리에 로드가 된다. word.exe는 메모리에 올라가야 실행되기 시작한다.

  • Run: 로드 된 이후 실행할 수 있다.

    • Runtime : 실행시점의 에러.

  • Terminate

Load 단계 부터 프로그램이라고 부르기 시작한다. 메모리에 적재된 그녀석을 프로그램이라 부른다.

프로그램을 우습게 보지 말라. 원자력발전소 프로그램을 개발한다고 생각해보라. 런타임 에러가 얼마나 끔찍한 일인지를 보라. 더 끔찍한 것은 런타임을 그냥 지나쳐가는 것이다.

급여 프로그램을 만든다면? 반으로 깎여 들어가는 경우나, 급여가 두배씩 들어가는 경우 등.. 논리적인 에러 수준을 보고 context error라고 한다. 팀의 커뮤니케이션에서도 해결해야 하는 부분이다.

런타임 에러는 재현도 힘들고 잡기도 힘들다. 이 에러가 안나게 하는 것이 우리가 추구해야 할 방향이다.

Script program

  • language Code

  • File

  • Load

  • Machine Language

  • Run

  • Terminate

스크립트 언어는 3단계에서 Machine Language로 변경한다.

Runtime

스크립트 언어는 런타임이 중요하다. 런타임을 이해하지 못하면 스크립트 언어를 이해하지 못한다. 공부를 한다는 건 이 분야의 용어를 정확하게 설명할 수 있다는 것이다.

메모리가 있다고 하자. 파일을 적재하면 통째로 적재하지 않고, 명령 부분과 데이터 부분을 나누어 넣는다.

Instruction fetch & Decoding
  • 실행하면 CPU로 보낸다.

  • 외부 입출력 인터페이스. (L3 Cache 같은 것) 명령이 들어가는 관문이다.

  • 제어 유닛이 디코딩한다. 추상명령을 cpu가 알수 있게.

  • 연산 유닛이 제어정보를 처리한다. 제어 유닛과 데이터 유닛에서 정보를 받아와서 처리한다.

  • 데이터 유닛은 데이터를 받아온다.

다시 런타임

우리는 language code에서 변수를 선언했다. 이 시점에는 load되지 않은 상태이다. 그렇다면 어떻게 된 걸까? 물리적 메모리를 가지고 있지 않는데, 어떻게 a+b = 7을 어떻게 검증할까? 컴파일러가 어떻게 검증했을까? 컴파일러가 가상 메모리 상에서 메모리 할당하여 실행해보고 결과를 계산해 본 것이다.

실제 메모리는 load 할 때 생긴다. 가상 메모리 A를 진짜 메모리 A에 할당하는 것이 v-table이다. 컴파일 언어에서는 다 있다.

  • essential definition loading

  • v-table mapping

  • run

  • runtime definition loading

  • run

script program

  • declare base function, class...

  • declare extended function, class...

  • use function, class...

각 단계는 서로 상대적으로 static time, run time으로 볼 수 있다. 컴파일 타임이 없다보니 레이어를 쳐서 나누어 구분한다.

Memory, address, pointer, variables, dispatch

방금까지는 프로그램의 생명주기를 이야기함. 적재된 프로그램 안에서 무슨일이 일어날까? 메모리 이해가 최우선이다. 명령은 적재되서 차근차근 빼서 실행한다. 우리가 봐야 할 건 데이터이다. 우린 개발할 때 유연성을 위해 참조의 참조를 쓰는데, 실제 세계에서는 링크드리스트, 인터페이스와 구상클래스, 클래스와 인스턴스, 데코레이터 패턴, 비지터패턴, 컴포짓 패턴 등...을 응용하기 때문에 참조의 참조라고 알 수 있다.

메모리 -> 주소 -> 포인터 -> 변수 -> 디스패치

메모리를 보면, 고유한 번호를 갖는 블록체계로 되어 있다. 블록 크기는 얼만지 모르지만, 블록을 나타내는 주소가 몇자리인지는 알 수 있다. (32bit, 64bit 등..)

주소 하나당 블록 하나를 갖는다고 생각해보자.

A = "TEST"를 갖고 어딘가의 메모리에 TEST가 들어갔다고 생각해보자.

A 변수 주소가 11번이다.

A="TEST", &A=11이고, B=&A를 하면, B에는 11이라는 주소값을 가진다. B를 통해 TEST를 알고싶다면, *B = "TEST" 가 나온다.

어떤 변수는 값, 어떤 변수는 주소를 넣고, 또 값을 얻을수 있다. 변수를 만들면 퍼져나간다.

C = B, D = B 등… 한번 변수가 만들어지면, 그 여파는 퍼져나간다.

근데 B가 k를 가리킨다면? C, D는 원래 B를 예상하지만, 그렇지 않다. B가 배신 때려버렸기 때문. 이 문제를 해결해나가는 것이 프로그래밍이다. 참조를 복사하면 이런 문제가 꼭 일어난다.

함수형 패러다임에서는 참조를 쓰지 마라고 한다. 참조는 악의 근원. 값만 쓰라고 한다.

객체지향에서는 직접 참조하지 말라고 한다. 오늘은 직접 참조하지 마에 대해 배운다.

----

B = { value: &A, V:3 }, C = B; D =B;가 있다고 하자.

01번지에 object가 들어간다. value와 v에 대한 정보를 담고 있다.

value에 대한 정보는 9번지에 11이란 주소를 담는다.

v에 대해서는 16번지에 3을 저장한다.

B는 01번지를 가리킨다.

B는 A를 소유하지 않고, 한번 쿠션을 쳐서 들어간다. 이것이 참조의 참조이다.

A의 값을 얻기 위해서는 B의 value를 조사해야 한다.

주소로부터 값을 얻는 행위를 dispatch라고 하는데, 이 경우는 double dispatch라고 부른다. B.value가 바뀌어도, 등식이 성립하게 된다.

Lexical grammer

  • Control character (제어 문자) : 우리말에는 없음. 중동계열 문자가 있음

  • white space (공백 문자): a = b; 에서 공백은 0020인데, 한칸 띄워주는게 굉장히 많다. 공백 중 어떤 것을 공백으로 쓸 수 있을까? 정의

  • Line terminators (개행 문자): 한 줄을 끊는 문자. 5종 이상 있다.

  • comments (주석): // /**/

  • keyword (예약어): 원어에서 예약된 것들. 변수, 식별자로 안 봄.

  • Literals (리터럴): 더이상 나눌수 없는 객체나 표현. 숫자 37을 '3', '7'을 왜 37로 인식하나? 숫자로 표현하는 더이상 나눌수 없는 숫자 리터럴이다. -37, -37.5, .5 등... 숫자리터럴만 10종이 넘는다.

이걸 다 배우냐? 부담느끼지 말고... 이렇구나 정도는 이해해라.

Language Element

  • statements (문): 공문, 식문, 제어문, 선언문, 단문, 중문

    • 컴파일러 혹은 실행기에게 주는 힌트. function 이라는 문은 문이 아닌 식으로 처리 됨. while이나 for를 사용하면, 실행하고 나면 실행된 결과 등이 흔적이 남지 않는다. 이 힌트를 받아들여 처리만 하고 메모리에 남지 않는다.

    • for (var i= 0; i < 5 ; i++);해도 에러 안남

    • ;;;;도 에러 안남. 공문을 인정하기 때문

    • 선언문: const, let 등

    • 아까 a는 메모리 주소의 별명. a주소는 11번지인데, 타입, 크기를 알고 있다.

    • 변수: 메모리 주소의 별명

    • a의 실체

      • 주소 11번지

      • 변수의 크기나 종류가 설정

      • b는 참조 형 변수, a는 값형 변수. 타입이 정해져 있고 또 a 는 크기가 얼마인지 우리가 알고 있다.

      • TEST라는 글자 읽기 위해서 a 에 11번지 부터 시작해 4 블럭만 읽으면 된다는 정보도 알고 있다.

      • 메모리 주소가 어딘지와 얘가 어떤 타입인지 와 메모리를 어디까지 크기를 갖는 지를 알고 있다. 이 정보를 합쳐서 v 테이블에 써놓는다. 그러면 실제로 메모리에 적재 됐을 때 v테이블의 참조 내용을 보고서 실제 메모리에 그만큼 확보해 가지고 애한테 진짜 주소 매핑 해 주고 프로그래밍이 시작되는 것.

    • 중문, 단문: 어떻게 구문을 해석하는지를 알자

      if (true) a = 3;
      else if (a > 2) b =3;
      else b = 5;

      // 위는 아래와 같이 해석한다.
      // js에서는 중문 쓸때, object 리터럴, 함수 리터럴에도, 클래스 리터럴에도 사용한다.

      if (true) a = 3;
      else {
      if (a > 2) b =3;
      else b = 5;
      }

      const f = (a) => {} // 이것과
      const f = (a) => ({}) // 이것은 다르다. {}가 여러군데 쓰이기에 구분을 해주는 로직이 깔려있다.

  • expression (식): 값식, 연산식, 호출식

    • 식 = 값이다. 값을 표현하는 방식

    • 3

    • 3 + 5

    • 3;5;6;도 안죽는다. 다른언어는 죽는다. 식문이 성립하기 때문.

  • Identifier (식별자)

    • 변수

Sync flow

제어문은 무엇으로 제어하나? 흐름으로 제어한다.

프로그램의 실체는 메모리에에 적재되어 있는 명령어의 연쇄. 도중에 못 멈춘다. fetch - decode- excution...의 연속이기 때문. 동기화 작동. 메모리 적재된 중에는 우리가 간섭을 못함. 메모리 적재된 명령어들을 우리가 건들 수 없다. 코드 짜면 좌에서 우로, 위에서 아래로 성립시킨다고 가정한다.

왜냐하면 명령어가 순차적으로 흐른다 생각하기 때문. 사실 이건 서양인 센스이다. 사실 우리는 우측에서 좌측으로 글을 읽었다.

sync flow에 제어를 하는 것은 sync flow control이다. if나 for 문… 일자로 흐르는 흐름을 바꿀수 있기 때문.

sub flow

필요할 때 불러서 쓰는 것. Control flow와는 다름. 보통 함수와 클래스를 이용하여 쓴다.

Comments