제품을 만들다보면, 내가 작성한 코드, → 제품도 결국에는 시간이라는 요소로 인해 레거시가 된다. 레거시가 된 나의 코드. 내가 생산한 그것이 해석하기 좋은 레거시가 되길 바라고 있다. 하지만 당연히 어려운 부분이고, 아직도 당당하냐고 묻는다면 아니다. 부끄로운 코드를 많이 작성하고있다. ;; ㅎㅎ
좋은 레거시란 무엇인가? 누군가 와도 쉽게 유지보수 할 수 있는 제품. 코드라고 상각한다. 혹여나, 짱구처럼 이게 모야모야?라고 말할정도로 바로 받아들일 수 없어도, 컨텍스트와 상황을 설명하면 이해는 할 수 있는 코드는 되어야 좋은 레거시 범위에 포함할 수 있다고 생각한다. (따지고보면 비단 개발 분야에만 해당하는 말은 아니긴하다.)
요즘과 같은 업무환경에서 나의 몸 하나, 나의 한정된 리소스에서 어떻게 빠르게 효율적으로 치고 나갈 수 있는지. 고민하는 요즘, 이 책은 현실적으로 나의 뇌가 어떤면에서 한정적인지에 대해서 말해주고, 이러한 한정적은 환경에서 어떻게 전략적으로 활용할 수 있는지 이야기해준다.
책에서 이야기하기를 코드를 생산하는 것보다 해석하는 것이 업무의 반 이상이라고 한다.
즉, 누군가가 내가 만든 길을 접근할 때, 그 길을 잘 따라 올 수 있도록 네비게이션을 해두어야한다는 것이다. 코드에서의 UX를 잘 구축해 두는 것이 중요하다는 것.
개발을 한다는 것은 결국 문제해결을 위한 것인데, 해결해야하는 문제 자체가 복잡할 수가 있다.(책에서는 이를 내제적 인지부하라고함) 이는 컨트롤할 수 없으니, 컨트롤할 수 있는 인지부하는 최대한 낮춰야한다. 이 책에서는 컨트롤 할 수 있는 외제적 인지부하에 대해서 주로 나온다. (내제적 인지부하를 어떻게 잘 해석할 수 있는지도 나오긴함) 의도한 목적을 잘 전달하는 것을 목표로 해야하는데, 그러기위해서는 여러 장애물들을 낮춰야하고, 인지부하를 낮추는 행위로 귀결된다.
결국에는 제품을 만드는 입장에서는 해석하기 쉽도록, 유지보수하기 쉽도록 만들어야한다.
단순 명료하게,
첫 챕터에서 “코딩 중의 혼란” 이라는 챕터가 나온다. 3가지 개념이 나온다.
읽는 사람이 인지부하가 안오도록 해야한다.
- 지속가능한 데이터를 활용하기 위해 볼륨을 사용할 수 있으며, 호스트볼륨을 공유하거나, 볼륨컨테이터를 만들어 활용하거나, 도커 볼륨을 활용할 수 있다.
- 도커는 컨테이너 내부IP를 순차적으로 할당하며,(컨테이너 별로 내부망이 생성) veth 인터페이스로 접근가능하다. 도커가 자체적으로 제공하는 5가지 네트워크 드라이버가 존재한다.
- 도커는 컨테이너의 표준출력과 에러출력을 별도로 메타데이터 파일로 저장하며, 이를 확인가능하도록 한다. 로깅을 도와주는 써드파티 드라이버들도 존재한다.
복사개념으로 컨테이너 directory를 host directory에 마운트한다.
예시
컨테이너 2가지 생성
1 | ❯ docker run -d \ |
/home/wordpress_db
)를 Host directory(/var/lib/mysql
)에 마운트-v
: [호스트 공유 디렉토리]:[컨테이너의 공유 디렉터리] -v /home/wordpress_db:/var/lib/mysql
1 | ❯ docker run -d \ |
wordpressdb_hostvolume:mysql
-v
[호스트 공유 디렉토리]:[컨테이너의 공유 디렉터리]-volumes-from
)-v
옵션으로 볼륨을 사용하는 컨테이너를, 다른 컨테이너와 공유하는 것
A 컨테이너 생성시 —volumes-from
옵션 설정하면-v
옵션 적용한 컨테이너(B)의 볼륨 디렉터리를 공유할 수 있다.
1 | docker run -i -t \ |
여러개의 컨테이너가 동일한 컨테이너에 —volumes-from 사용하여 볼륨을 공유해 사용할수도 있다.
도커 자체에서 제공하는 볼륨기능을 활용해, 데이터를 보존할 수도 있다.
1 | docker volume create --name myvolume |
-v
사용. 컨테이너 디렉토리만 넣어두면, 도커볼륨 자동 생성1 | docker run -i -t \ |
1 | [볼륨의 이름]:[컨테이너의 공유 디렉토리] |
docker volumn prune
veth..
라는 네트워크 인터페이스를 생성함으로써 이루어진다.veth
: virtual eth1 | root@75308a74b2c2:/# ifconfig |
컨테이너 생성시
docker0
브릿지를 통해, 외부와 통신할 수 있는 환경을 사용할 수 있다.1 | ❯ docker network ls |
사용자 정의 브릿지를 새로 생성해, 각 컨테이너에 연결하는 네트워크 구조.
컨테이너는 연결된 브릿지를 통해 외부와 통신 가능
브릿지 생성하기
1 | docker network create --driver bridge mybridge |
--net
옵션으로 컨테이너가 네트워크 사용가능
1 | docker run -i -t --name mynetwork_container \ |
네트워크 연결: docker network connect
네트워크 분리: docker network disconnect
--net-alias
--net-alias
172.18.0.3
~ 5
)1 | ❯ docker run -i -t -d --name network_alias_container1 \ |
Docker DNS, Round-Robin 방식
Round-Robin
dig
라는 명령어로 확인가능.Docker DNS
—-link
: 컨테이너의 IP가 변경돼도, 별명으로 컨테이너를 찾을 수 있게 DNS에 의해 자동관리--not-alias
: 도커는 사용자가 정의한 브릿지 네트워크에 사용되는 내장 DNS 서버를 갖는다.alicek106
이라는 호스트 이름으로 등록됨1 | docker run -i -t --name mynetwork_host \ |
말그대로 아무런 네트워크를 쓰지 않는 것.
lo
외에는 존재하지 않는다.1 | docker run -i -t --name mynetwork_none \ |
1 | docker run -i -t --name mynetwork_none \ |
StdOut
과 에러 StdErr
로그를 별도의 메타데이터 파일로 저장하며, 이를 확인하는 명령어를 제공한다.docker logs
--since
옵션에 유닉스 시간을 입력함. 특정시간 이후의 로그를 확인할 수 있다.1 | docker logs --tail 2 mysql |
1 | docker logs -f -t mysql # 전체 출력 |
위와같은 컨테이너 로그는 JSON형태로 도커 내부저장
1 | cat /var/lib/docker/container/${CONTAINER_ID}/${CONTAINER_ID}-json.log |
json 파일 크기가 계속 커질 수 있어서, 호스트의 남은 공간도 전부 사용할수도 있음.
도커의 기본적인 로그뿐만아니라, 드라이버로도 로그 가능
도커 환경으로 구성된 인프라들을 최근들어 자주 접하게 되고, 프론트 리소스도 도커, 쿠버네티스 환경에서 운영됨에 따라, 프론트 개발자도 이에 대한 지식이 필요하다고 느껴 스터디를 진행합니다. 스터디는 “시작하세요 도커/쿠버네티스” 책으로 진행합니다.
도커 환경으로 구성된 인프라들을 최근들어 자주 접하게 되고, 프론트 리소스도 도커, 쿠버네티스 환경에서 운영됨에 따라, 프론트 개발자도 이에 대한 지식이 필요하다고 느껴 스터디를 진행합니다. 스터디는 “시작하세요 도커/쿠버네티스” 책으로 진행합니다.
리눅스 컨테이너에 여러 기능을 추가하여
→ 어플리케이션을 컨테이너로서 좀더 쉽게 사용할 수 있게 만들어진 오픈소스 프로젝트
커널? 운영 체제(OS)의 주요 구성 요소이며 컴퓨터 하드웨어와 프로세스를 잇는 핵심 인터페이스
1 | {{ 저장소 }}/{{ 이미지 이름 }}:{{ 태그 }} |
도커 GUI 클라이언트 사용하며 익히면 굳
docker run -i -t ubuntu:14.04
(1. ubuntu:14.04 이미지 기준으로 pull
, 2. 컨테이너 생성 create
, 3. 내부 진입 attach
)exit
(컨테이너 정지 + 나감), Ctrl+P,Q
(그냥 나감 (정지 않함))docker ps
(정지되지 않은 컨테이너만 출력) (-a
정지된 것까지 출력)docker rm
(복구 불가능/ 실행중인것은 삭제 불가능), docker container prune
(모든 컨테이너 삭제)eth0
), 외부 노출 가능eth0
의 IP포트를 Host의 IP와 포트에 바인딩 해야함docker run ... -p 81:80 ubuntu:14.04
1 | docker run -i -t --name joy ubuntu:14.04 |
-i
: 상호 입출력-t
: tty를 활성화 (bash shell 사용하도록 설정)--name
: 컨테이너 네이밍1 | docker run -d --name detach_test ubuntu:14.04 |
1 | docker exec -it {{ 컨테이너 이름 }} /bin/sh |
1 | docker pull // 원격에 있는 이미지 풀받기 |
2021년에는 무엇을 선택해야 할지 감을 잡았고
2022년에는 그 선택에 집중하기로 마음먹었다.
이전 회사를 3년 정도 다니고 올해 초 3월에 회사를 이직했다.
새로 다니게 된 회사는 정말 만족스럽다. 제일 만족스러운 부분은 회사 문화인데, 특히나 개발 문화가 너무 좋고, 서비스를 만드는 maker들 간의 관계도 만족스럽다. 문화가 좋아서 그런지 동료들도 건강하고 멋있는 사람들이 많다. 다들 회사의 성장 == 개인의 성장하려는 욕심들이 있고 이를 위해 건강한 논쟁도 하고, 빠르게 오버컴케하며 서로 존중하며 앞으로 나아간다.
이들 사이에서 함께 업무를 하는 과정에서도 많이 배우고 있다. 건강한 논쟁, 효율적 협의, 그리고 경험을 통한 레슨런을 다음 액션에서 녹일 수 있도록 서로 독려해주는 태도 등등. 적다 보니 좀 이상적이긴 하니 한마디 적어보면 이 부분들이 100% 완벽하게 성숙한 상태라고는 말할 수는 없지만, 방향은 이미 잘 조준되어있다고 본다.
입사 이후에 6개월? 7개월은 계속 회사 일에 집중했다. 회사 적응도 해야 하고, 들어가게 되었던 스쿼드도 달리는 마차이다 보니, 들어오자마자 바삐 움직였다. 회사 적응과 업무를 동시에 하다 보니 집에 오면 개발 일을 전혀 하지 않고, 휴식에 집중했다. 짧게 설명했지만, 물리적인 시간 관리 이외에도 여러 가지 관리해야 할 포인트들이 많아졌다. 그 안에서 지금의 리듬을 찾는 데에서 많은 시행착오가 있었다. 사실 지금도 시행착오이긴 하지만 😇
내가 소비하고 생산하는 모든 것들을 조화롭게 관리하기 위해서는 적절한 선택을 하고 이 선택의 책임은 온전히 내가 갖는 것, 그리고 이런 과정을 누군가와 함께 할 때 계속 나아갈 수 있다는 것을 몸소.. 체험하며 깨달은 한 해라고 생각한다. 그리고 이 레슨런은 자연스럽게.. 좀 더 자립심을 갖게 해준 것 같다.
업무를 보다 보면, 선택과 집중을 해야 하는 부분 때문에 다른 것들을 놓치는 상황이 온다. 리소스는 한정되어있고, 목표가 아닌 것보다 목표해야 하는 것을 달성해야 하기 때문이니 당연한 순리다. 이렇게만 태도를 취하고 달려도 언제나 일정은 빠듯하다.
2개월 전 즈음에 CTO님이 합류하셨다. 정기적인 미팅으로 업무얼라인을 진행하곤 하는데, 종종 적절한 상황에 맞게 조언이나 격려의 말을 해주신다. 아직 배워야 할게 많아서 그런지 모든 말들이 주옥같았다. 그 와중에, 이런 말씀을 하셨다. “누구나 리소스는 한정되어있습니다. 누구나 한정되어있고, 그 한정된 시간 안에서 문제를 해결하는 것이 엔지니어의 역량입니다…” 교양서적에 나올 법 한 문장이고 자주 만났었던 문장이다. 리소스 관리, 문제해결 능력에 대한 고민을 하게 해 준다.
한정된 리소스를 어떻게 효율적으로 할지, 불필요하게 소비하지 않고 생산성 있게 소비할 수 있을까를 좀 더 객관적으로 바라보려고 한다. 다 펼쳐놓고, 어디서 물이 새고 있는지 메꿀 수 있는 방법은 무엇인지 고민하고 해결하는 2022년이 될 듯하다.
]]>채워지는 bar의 Corner 부분!
생각나는 방법은 3가지가 있다.
1번과 2번의 경우 base bar와 채워지는 bar 2가지 모양을 만들어서, 채워지는 bar의 corner를 대응해야한다.
1번의 경우 부자연스러움이 걱정되었고, 2번의 경우 구현하는 방법이 상상이 되지 않았다.
3번의 경우 2가지 bar를 만드는 것이 아닌, 하나의 bar에서 채워지는 속성을 컨트롤하여 구현하기 때문에 1번 2번보다 자연스럽게 구현할 수 있다고 생각하였다.
또한 svg로 선택할 경우 그래프 이외에 커스텀한 디자인이 추가될 경우 대응이 가능하기때문에 3번 방법으로 선택하여 구현해보았다.
해당 포스팅은 3번 구현에 대한 내용을 작성하려고한다.
3번으로 진행할 경우 2가지 케이스를 확인해야한다.
기타) 애니메이션도 챙겨보자.
Svg
와 그라데이션⚠️ 이 방법을 사용하기 전에 전제조건은,
디자인이 모두 flat한 형태의 디자인일 경우에만 가능하다. 만약 채워지는 bar의 fill이 단색이 아니라 디자인이 추가되어있을 경우 사용할 수 없다.
svg는 형태를 만들고, 그 안을 fill로 채울 수 있다. prgress bar에서의 100%를 향해 채워지는 형태로 생각해보았다.
현재 svg에는 색상을 나눌 수 있는 속성은 따로 없다. 대신 그라데이션 효과를 사용하면(linear gradient) fill에 2가지 이상의 색상을 줄 수 있다. 그라데이션은 2가지 이상의 색상을 정의하고, 색상의 position을 정의하면, 각각의 위치에서 서로의 위치 사이의 색상이 점진적으로 정의된다.
여기서 각각의 poisition을 동일하게 둘 경우, 둘 사이의 정의할 색상이 존재하지 않기 때문에 색상이 2가지 단색으로 존재할 수 있다.
위 그림의 중앙 point를 오른쪽으로 움직이면 왼쪽에서 오른쪽으로 채워지는 형태가 될거라고 기대할 수 있다.
그래프가 고정형이 아닌 모바일 대응을 해야할 경우, 폭을 대응해야한다.
높이는 유지하고 폭을 대응해야하기 때문에 scale로 늘릴 수는 없다. (정비율로 커지기 때문에)
방법은 shape의 point를 옮기는 방법이 있다. 아래와 그림과 같이 가장 오른쪽의 point들을 늘리면 된다.
bar는 rect 태그를 활용하여 구현한다. rx에는 radius의 값을 추가한다.
1 | <rect x="0" y="0" width="200" height="50" rx="8" fill="none"/> |
to
속성에 비율을 정의하면 된다. (0 ~ 1사이)offset
속성에 비율을 정의하면 된다.1 | <svg ...> |
셋팅은 여기 레포에서 확인 가능하다.
최근 버그와 관련된 CS가 인입이 되어, 픽스 후 배포했음에도 불구하고 유사한 CS가 인입이 되었을때 또 다시 버그 개선 티켓이 생성되곤 했다. 버그 픽스가 제대로 되지 못했을 수도있지만, 상황을 확인해보면 이슈를 CS단계에서 확인하지 못하고 바로 넘어오는 상황이 많았다. (커뮤니케이션으로 해결가능한 것들도) 이런 상황이 반복되고 누적되다보니 개발 집중력이 떨어지고, 불필요한 커뮤니케이션에 시간을 쏟고 있다는 생각이 들어, 개선해야겠다는 생각이 들었다.
CS단계에서 진행되지 못하고 넘어올수밖에 없었던 이유
CSR의 경우 새로운 배포가 이루어졌을때, 새로고침을 하지 않을 경우 새로 배포한 JS파일을 바라보지 못하고, 이전 JS파일을 바라보고 있게 된다.
배포 notice를 확인할 수 있는 채널이 있지만, CS담당자가 이를 확인하지 못했거나, 잊을수도 있다.
사실 1번과 2번의 경우 SSR형태의 프로젝트나, 브라우저를 오래 유지하지 않고 사용하는 프로젝트라면 화면을 이동할때나 새로 들어갈때 최근에 배포한 파일을 load하기때문에 문제가 거의 발생하지 않는다. 하지만 어드민과 같은 프로젝트의 경우 브라우저를 끄지 않거나 컴퓨터를 아예 끄지 않는 경우 등, 오랫동안 새로고침하지 않고 유지되는 상황이 존재하기에 위 상황이 발생할 가능성이 있다.
생각나는 해결 방법은 아래와 같았다.
문제사항의 해결방향으로 다시 바라보면
해결방법 3번이 가장 효과적인 방법이긴하나, 이번 포스팅에서는..
해결방법 1,2번의 경우에 해당되는 버전관리, 배포내역관리에대해 작성하고자 했다.ㅎㅎ
버전관리와 배포내역 관리는 배포시점에 진행해야하는데, 생각나는 순서는 아래와 같았다.
버전을 업데이트하고, 배포사항을 내역에 추가하는 일련의 과정을 배포때마다 한다는 것은 여간 번거로운 일이 아니다. 직접 구현전에 자동화로 만들어 놓은 오픈소스를 찾아보고, 배포시점때마다 진행되어야해서 CI툴에 JOB으로 단계별로 생성하여 진행하기로 했다.
찾기전에 버전과 배포내역이라는 개념을 정리해볼 필요가 있었다.
두 가지는 오픈소스 프로젝트에서 자주 볼 수 있었다.
이를 참고하여 리서칭해보니 2가지 개념이 나온다.
시맨틱 버저닝의 경우 이 링크에서 자세히 확인 가능하다. 소프트웨어의 버전 변경 규칙에 대한 제안이다. 간단히 말하자면 의존성 지옥을 해결하고자 배포시 버전번호를 명시하여 정의를 내림으로써 의존성관리를 용이하게 한다. SemVer의 형태는 아래와 같다.
1 | MAJOR.MINOR.PATCH |
npm에서는 버전을 관리할 수 있는 cli를 제공한다.
이 명령어를 통해서 package.json의 버전명을 올릴 수 있다.
1 | npm version |
CHANGLOG
1 | // .versionrc |
release note
이 2가지를 관리할 수 있는 standard-version이라는 라이브러리가 존재한다.standard-version
스크립트 하나로 여러가지 일을 실행해주는데 아래와 같다.
chore(release): 버전명
하나 걱정되는 것은 기여자 모두가 conventional commit 스펙을 정확히 맞춰서 작성해야하는 부분이였는데
아래 라이브러리들로 해결이 가능했다.
컨벤셔널 커밋은 페이지에서 이렇게 설명한다.
프로젝트에 셋팅하지 않아도 커밋 습관을 들이기 좋은 컨벤션이라고 생각이 들었다.
형태는 아래와 같다.
1 | <타입>[적용 범위(선택 사항)]: <설명> |
즉, 위의 규격을 지키며 커밋을 진행해야한다.
(예시)
1 | fix: correct minor typos in code |
commitlint를 사용해 commit시에 컨벤션을 잘 지켰는지 체크한다. 컨벤션은 어느정도 규격화되어있다.
conventional-commit
을 따르려면 @commitlint/config-conventional
를 상속받아서 사용하면된다.1 | module.exports = { |
husky를 사용하여 셋팅하였다.
1 | // package.json |
npm version
명령어를 통해 버전을 관리하고, 1 | build: |
운영이슈에서 오는 피로감을 개선하고자 여러가지 방향을 고민해보았는데, 문제해결로 가다가 살짝 옆으로 샌감이 없지않아 있다.ㅎㅎ 무튼 덕분에 버전관리와 배포내역관리에 대한 라이브러리들 을 알 수 있었고 github액션도 사용해보아서 개인적으로 재밌었던 포스팅이었다.
참고자료
]]>[UX/UI의 10가지 심리학 법칙] 책을 읽으며 법칙별로
내용 요약 + 개인적으로 찾았던 레퍼런스 + 그밖에 자료들을 모아서 작성한 글입니다.
1954년 미국의 심리학자 : 폴 피츠
터치 대상까지 움직이는 데 드는 시간을 대상까지 거리와 대상 너비 간의 비율에 관한 함수를 통해 예측하면서 탄생
피츠의 법칙은 오늘날 인체 움직임에 관한 가장 영향력 있는 수학적 모델로 여겨지며,
피츠는 대상 선택 작업의 난이도 ID를 정량화하는 측정 기준도 제시했다.
터치 타겟의 개념에 3가지가 나오는데, 크기, 다른 요소간의 간격, 유사한 흐름에 배치
1 | .container a { |
@material/touch-target
라는 패키지를 제공하는데, 추가적인 sass파일을 적용시켜준다.기본 버튼
1 | <button class="mdc-button"> |
touch-target로 감싸기
mdc-touch-target-wrapper로 감싸고
mdc-button__touch를 추가해두었다. → 여기에 absolute로 height값이 지정된다.
1 | <div class="mdc-touch-target-wrapper"> |
touch-target의 scss 파일을 보면, height값과 width값에 default값으로 48px을 적용한 부분이 보인다.
마지막 margin부분은, 강제로 적용한 touch target 영역을 채우기 위해 margin을 추가적으로 적용하는 부분이 보인다.
아름답다.. 지금까지 scss를 잘 활용하지 못했다고 생각했다..
1 | // node_modules/@material/touch-target/_touch-target.scss |
스마트폰 form factor가 다양하다.
위 내용은 uxmatters의 글을 읽어보는 것이 더 재밌다. 해당 포스팅에서는 자세히 다루진 않겠다.
Design for Fingers, Touch, and People, Part 1
Design for Fingers, Touch, and People, Part 2
Design for Fingers, Touch, and People, Part 3
참고자료
.. 우리가 아는 프로젝트 대다수에서 그 어떤 기술적인 난관보다 사회적인 복잡도가 훨씬 더 컸다는 사실이 분명해 졌다. 그러면서, 불가피하게, 우리는 아주 속상한 결론에 도달했다. 다분히 사회학이 기술보다 더 중요하다는 사실을 오랫동안 느낌으로 알아왔으면서도 정작 우리 중 누구도 그렇게 관리하려 시도하지 않는다는 사실이었다. 물론, 때때로 팀의 협력을 돕거나, 팀 내 긴장을 풀어주기 위해 사회학적인 방법을 사용하기도 했지만, 한번도 우리 업무의 본질이라 여기지 않았다. … - ‘피플웨어’ 중
UX에 대해서 중요하다고 생각은 했는데, 항상 생각만하고 막상 공부나 여러가지 시도를 하지 못하고 있었다. 직감적으로는 알겠는데, 조금 더 스스로 정리하기 위해 해당 글을 작성하였다. 개인적인 견해이니 자유롭게 읽으면 좋을 듯 하다.
웹개발자를 직업으로 갖으면서 이런 생각이 든다.
제품을 잘 만들어서, 내 업의 성취감을 얻으려면 -> 재밌고 오랫동안 일하고 공부해야한다.
그동안 재밌게 일했던 순간들은 언제였을까? 어떤 조건이 있었을까?
프론트개발자로 일을 하면, 여러 유관부서와 협업하며 업무를 진행하게 된다. 디자이너뿐만아니라, 마케터, 기획자, 타 부서 엔지니어등. 그들은 내가 어떤 개발을 해야할지 알려주고, 개발을 요청해 오거나, 혹은 나 스스로가 일을 만들때도 있었다. 몇 년을 이렇게 프로젝트들을 진행하면서, 주변 피드백을 통해 나의 특이점을 찾게 되었는데, 흥미가 있는 프로젝트이거나, 이유가 명확한 프로젝트일수록 업무의 생산성과 속도가 올라가곤 했다. 그리고 그 마음가짐이 오래간다. (근데 모.. 이는 모두가 같을 것이다.) (흥미의 포인트는 개인의 관점일수도, 서비스의 관점일 수도있다.) 여기에 같이 일하는 사람과의 합이 잘 맞을 경우 몇 배나 더 즐겁게 일했던 기억이 난다.
이렇듯, 사람은 자신이 하는 일에 이유가 있다면, 업무 자체가 목표지향적이게 되어서 빠르게 치고 나갈 수 있는데, 최근 들어서 내가 공부하려는 프론트 skill들은 어떤 이유에서 비롯해서 공부해야하는지? 알긴알고 있지만, 그 이유, 동기들을 정리할 필요가 있다고 생각이 들었다. 굳이 모든 일에 이유를 찾을 필요는 없지만, 조금 더 재밌게 하기위해서는? 시간을 효율적으로 나눠서 공부하기 위해서는? 조금더 근본적인 이유를 찾을 필요는 있는 듯 하다. 그리고 공부가 재밌는 순간은 공부한 내용을 바로 활용할때..!이니, 이또한 고려가 되어야한다.
인터넷에 돌아다니는 XXX 로드맵들을 보고 있으면, 참 공부해야할게 많다. 브라우저 엔진에 대하여, 사용하는 언어의 최신문법, 특정상황에 필요한 기술들, 성능향상을 위한 알고리즘, 네트워크, DB, 아키텍처, 패러다임, 디자인 패턴 …
위 내용 모두 중요하다. 하지만 오랫동안 재밌게 공부하기 위해서는, 공부할 내용의 성격/분량/목적 등을 정리해서 꾸준히 공부할 수 있도록 해야한다고 생각했다.
웹 개발자는 웹 어플리케이션을 만들고, 사용자는 우리의 웹 서비스를 필요한 상황에 고용하여 사용한다. 사용자는 서비스를 사용하면서, pain point를 개선하게 되고, 이런 혜택을 제일 잘 얻을 수 있는 어플리케이션을 maker들은 ‘잘’ 만들어야한다. 나의 position은 maker에 속하며, 유저가 잘 인지하게 하고, 잘 input하고, 잘 피드백받을 수 있는 인터페이스를 ‘구현’하는 역할이다.
인터페이스를 만드는 maker에는 여러 유관부서가 기여하게 된다. PO, 디자이너, 클라이언트 개발자 등. 여기서 기여의 비중이 높은 순으로는 디자이너, 클라이언트 개발자라고 생각하는데 이 두 부서간의 교집합은 크다. 클라이언트 개발자가 백엔드 개발자와 커뮤니케이션을 많이 하는 만큼, 디자이너와의 커뮤니케이션 비중도 높다.
즉, 구현을 위해서는 시스템의 이해도, 기술력의 이해도를 높여하고, 사용성의 퀄리티를 올리기 위해서는 사용자 맥락의 이해도를 올려야한다.
‘잘’ 만들려고는 하고 있다.
여러가지 프로젝트를 하면서, 프론트개발자는 시각적인 부분을 구현하는 역할이지만, 제일 큰 킬링 포인트라고 생각되는 점은
구현 관점에서도 사용성을 올릴 수 있는 디테일한 포인트를 캐치할 수 있는 역할이 프론트개발자라고도 생각이 들었다.
의외로 구현하면서 “생각해보니 이렇게 하는게 좋지 않을까요?”라는 말을 많이 했던 기억이 난다.
즉,
이 외에도 단순하게 생각하면, 서비스의 수명이 오래가기위해서는 결국에는 두가지 포인트는(퀄리티 관점, UX관점) 병렬로 꾸준히 유지되어야 한다고 생각한다.
프론트 개발자도 이 2가지를 같은 레벨로 계속 습득하고, 유지해야한다.
요즘에는 가이드 툴, 프로토타이핑 툴, 인터렉션을 가이드할 수 있는 여러가지 도구가 나오면서, 디자이너가 사용성을 고민하고 시각화를 하거나 가이드안을 산출하는 상황이 많지만, 도움을 줄 수 있는 도구가 나왔다고 해서, 본질적인 부분, 즉 이 교집합인 부분의 지식을 습득하는 것은 여전히 중요하다고 생각한다.
프러덕트 개발은 항상 리소스는 한정되어있는 상황에 마주한다. 이런 상황에서도 좋은 퀄리티의 제품을 만들기 위해서는, 정확한 방향을 잡고, 병렬적으로 여러 사람이 제한된 시간에 많은 아이디어를 내고, 디테일한 부분까지 챙기면서 구현하는 것이 이상적이지만 중요한 부분이라고 생각한다.
프론트 개발자의 성장관점에서는 구현의 퀄리티와 사용성의 퀄리티의 우선순위로 보면, 당연히 구현완성도를 높이는 기술력 습득이 1순위이다.
사용자 경험 패턴을 지식으로 습득하지 않고, 기저에 있는 심리학 법칙을 이해하고 사용한다면, 훨씬 더 설득력 있는 인터페이스로 이어질 것이다. - UX/UI의 10가지 심리학 법칙
내가 왜 이 기능을 구현해야하는지. 이 부분은 왜 기본적으로 지켜야하는지를 알기 위해 사용자의 근본적인 심리학과 관련된 책을 읽어보고자 한다. 책은 [UX/UI의 10가지 심리학 법칙]이며, 아마.. 이 책을 다 읽으면 다른 책을 선택해보지 않을까 싶다.
해당 책은 10가지 심리학 법칙이 나오는데, 법칙들을 읽으면서, 이런 기본적으로 갖고 있는 심리를 유지하기 위해서는 어떤 기술력이 필요로할지 정리하고, 앞으로의 공부방향과 공부분야의 중요성을 이 법칙을 기준으로 정리해보고자한다. 또한 이런 심리를 고려해서 어떤식으로 구현했는지를 정리해보고자한다.
두 분야 다 알야아하는 부분
구현관점
시각디자인 관점
2019 회고 + 2020 다짐 (feat. 글또) ➔
작년 글을 보면, 웹 프론트엔드 개발자로써, 실력향상을 위해서 잡아두었던 계획들이 있었다. 구체적인 일정이나 어떤 방법으로 공부할지는 작성하진 않았었고, 우선순위, 중요도 정도로 작성해두었는데, 결론은 ㅎㅎ 하나도 못했다.. 대신 다른 관심있는 분야 위주로 공부를 하긴했는데, 잡아두었던 방향과는.. 유사한부분도 있고, 아닌 부분도 있다.
요약 회고
요즘 나의 공부스타일로 봐서는, 아예 날짜를 정해서 계획하고 실행했으면 공부를 했을텐데, 블로그에만 작성하고 다른 관심사가 생기면 해당건들을 공부하거나, 현실에 더 필요한 분야를 공부하다보니 놓쳤던 듯 하다.
음.. 어떻게보면 오히려 해당 프로젝트는 회사에서 유사하게 진행하였다. 다만, 토이프로젝트에서 녹이고 싶었던 부분은, 조금 더 인터렉션 기술이 많이 녹아져 있는 페이지였으면 좋겠다는 생각이였는데, 회사 프로젝트로는 정말 딱 통계 프로젝트 형식으로 진행되고 있어서, “데이터 기반” 이라는 컨셉은 같았지만, 원하는 리포팅 페이지 스타일은 아니였다.
그래도 데이터 기반으로 어떻게 집계해서 보여주는게 좋을지 등등 통계화면에 대한 기획은 배울 수 있었다.
올해는 정말 다이나믹한 해였다. 다양한 일을 해보면서, 개인적으로는 내가 잘 하는 부분, 노력하면 잘 될것 같은 부분, 잘 못하는 부분 등. 여러가지 성찰도 해보고, 개발자로써는 어떻게 크로스되는 방향으로 나아가야할지, 그리고 어떻게 하면 함께 잘 일을 해야할지. 고민을 많이 했던 해라고 생각된다. 그리고 그 고민의 해결에는 주변에 도와주는 많인 이들과 책이 있었다.
올해는 기존에 같이 일하는 분들 이외에 비개발자 직군들과 새로 입사하신 개발자분들 등, 나와 다른 관점을 가진 사람들과 일하는 상황이 많이 있었는데, 그때마다 어떻게 일을 해야 효율적인지(생산성), 어떻게 커뮤니케이션을 해야 효율적이고 피로도가 덜 쌓일지(프로세스), 어떤 태도를 가져야 곱하기로 나아갈 수 있을지 고민을 많이 하게 되었다.
때문에 시간할당이 개발에만 몰리진 않았었는데, 처음 있는 일이다보니, 혼란이 왔지만(내가 이런 고민을?), 결론적으로는 팀을 위한 고민이다 생각을 하니, 같은 업무 레벨로 봐야겠다는 생각이 들었다.
이 고민의 해결에는 책이 정말 많이 도움이 되었다. 그 중에 꼽자면, 피플웨어라는 책과 함께 자라기라는 책이 있는데, 함께 자라기는 입사하고 완전 주니어시절에 읽었지만, 올해 다시 읽어보면서 2년이 지난 이 시점에 또 다른 면을 볼 수 있게 되었다.
피플웨어라는 책은 개발자가 읽기보다는 개발자와 함께 일하는 비개발직군들도 꼭!! 읽어야하는 필수책이라고 생각한다. 지식노동자인 개발자와 건강하게 함께 일할 수 있는 노하우가 담겨져 있는 책이라고 생각한다.
기존에 존재하고 있던 분위기에서 어떤 문화를 녹이는 것을 많은 시도가 필요하다. 계속 나아갈 것은 유지하고, 개선해야할 부분은 하나씩 개선해나가면서, 우리에 맞는 색을 찾는 것이 중요하다고 생각한다. 그렇게 만들게 된 회사의 분위기와 문화로 인해 어느새 회사에서 일하는 업무가 내가 일하고 싶은 업무로 변하게 되고, 이는 나의 성장과 회사의 성장이 일치되는 순간이라고 생각한다. 이런 분위기에서 낼 수 있는 시너지란 곱하기 이상, 제곱이 될 수 있지 않다.
개발자가 재밌게 일하고 잘 일하게 만드는 문화란 무엇일까 고민하며, 우리의 상황에 맞게 만들어가려고 팀 내에서는 많은 고민을 하고 있다. 여러 번의 회고 등을 통해서 하나씩 잡아가고 있으며, 이런 과정이 잘 이루어지고 다른 포지션에도 전파되길 기대하고 있다.
올해는 여러가지 분야에 대해 알야아하는 환경이 되다보니, 모르는 분야를 접하는 순간도 많았고 때문에 이를 해소하기 위해서 스터디, 인강, 책 등 여러가지 공부 방법을 찾아보려고 했다. 시도 끝에 책을 보는 것을 메인으로 잡고, 나머지는 스터디나 인강을 통해서 보충하거나 다른 시야를 접하는 방식이 나한테 맞는 공부법이라는 것을 깨달았다.
또한, 작년에 진행했던 http 완벽가이드 스터디를 (마지막에는 살짝 흐지부지 됐지만) 마친 후, 책을 보는 것에 대한 두려움이 예전보다 많이 감소했다. 특히나 이 책이 400쪽 가까이 되는 두꺼운 책이어서 더더욱 그랬던 듯 하다.
그리고 올해는 6월부터 PO 책모임인 프만사(프러덕트 만드는 사람들)라는 책모임에 참여하면서 습관 붙이기에 더 불이 붙었던 듯 하다. 물론 이 모임도 중간에 정신없는 상황때문에 참여가 더디긴했지만, 책을 읽고 모임때는 모임장이 발제한 질문에 서로 얘기하는 분위기가 책에 대한 거부감을 줄여주었던 것도 있었다. 특히나 모임장인 민지님의 독서 열정을 보고 있으면, 더더욱 큰 효과가..
외부 책모임에서 얻은 좋은 경험을 사내에도 전파하고 싶어서, 여러가지 책모임들을 스멀스멀 진행해보았었다. 제일 재밌었던 책은 “빅데이터를 통한 예측마케팅”이라는 책과 “손에 잡히는 10분 정규표현식”이였는데, 책을 읽고 책모임 인원들이 회사의 업무에 바로 적용하던 모습이 인상깊어서 그랬던 거 같기도 하다.
내년 상반기까지 글또에 글을 작성할 예정이다. 13번의 글을 작성한다고 하는데, 어떤 글을 써볼까
올해는 코로나의 여파일지는 모르겠지만, 참 순식간에 지나갔다.
빠르게 지나가는만큼, 기록과 회고는 중요하니 꾸준히 성찰, 개인 성장, 함께 성장, 되돌아보기를 지치지 않게 해나가보자!
많은
데이터를 수집할 것인가설계 원칙
빈도 : 얼마나 자주, 어떤 촉발이벤트에 의해 데이터를 수집할 것인가?
파생 데이터 : 파생 데이터는 원 데이터에서 의미를 추추출하여 만든 데이터 요소이다.
웹사이트를 방문하고
제품을 5회 탐색한 후
7일 이내에 상점에서 구입하는 고객은
⇒ 온라인으로 정보를 수집하지만, 오프라인에서 구매하는 고객이라고 분류할 수 있다.
세분 가능성 granularity : 웹 데이터는 클릭 하나하나 각기 수집될 수 있고 웹 세션에 대한 요약만으로 충분한 경우들도 있다.
일단 모든 데이터를 한곳에 모으게 되면, 이 데이터를 사용하여 비즈니스와 고객을 더 잘 이해할 수 있다.
질문은 예측마케팅을 시작하는데 도움을 줄것이다.
cluster
clustering
, segmentation
segmentation
clustering
response models
= 우도모델 likelihood
)경향성 모델은
과거의 사례들을 통해 학습함으로써,
고객의 미래 행위를 예측해낸다는 점
반응모델 response models
라고도 종종 불린다.
우도 모델 (likelihood
,가능성)
가이드 학습 guided-learning 모델이다.
= 데이터를 학습하는데 시간이 걸린다는 것
= 시간이 지남에 따라 모델이 더 나아진다는 것을 의미
deciles
예측분석이 널리 보급되기 전에는 RFM이라고 불리는 모델이 구매 가능성이 높은 사람을 파악하는 업계 표준 방식이었다.
이 모델의 핵심 아이디어는
데이터에서 파생될 수 있는 많은 다른 변수들 중에는 추가적으로 우수한 예측 변수로 사용할 수 있는 것들이 있지만, 이 모델리에서는 변수 사용을 많이 안하는 방법이다.
과거의 결과가 미래의 성과를 보장하지 못한다가 적용되는 방법이다.
한 고객의 현재 행동을 과거 다른사람들의 이후 행동과 비교하기 보다는,
오로지 해당 고객의 과거에 대해서만 되돌아본다.
높은 가치의 고객이 실제로 구매를 하기 전에는 이들을 인지할 수 없다.
예
구매 가능성 매우 높음
이라는 세그먼트에 배치할 것이다.구매가 빈번한 환경에서만 향후 구매할 가능성에 대한 예측을 할 수 있다.
reinforcement learning
, collavorative filtering
)추천
실시간
으로 갱신되어야 함상향 판매 upsell 추천
후속 판매 next sell 추천
교차 판매 cross sell 추천
함께
구입하는 제품들참고자료
]]>예측마케팅은 예측분석을 사용하여서 고객접점마다 고객과 더 관련성 있고, 의미 있는 고객경험을 제공하고, 이를 통해 고객 충성도와 수익을 향상시킬 수 있다. 고객들도 개인화 접근방식을 원하며, 잘되는서비스들 또한 이를 증명해내고 있으며, 마케터들도 쉽게 다가갈 수 있는 좋은 솔루션들이 나오고 있다. 고객의 평생가치와 지갑점유율의 최적화에 초점을 맞추고, 고객관련성이 핵심지표가 된다.
customer equity
수익성을 높이기 위해 고객평상가치와 지갑점유율 share of wallet을 최적화하는데 중점을 둔다.
더 타게팅된 고객 의사소통이 이루어지며,
도달 범위가 아니라 고객관련성 relevance이 핵심 지표가 된다.
고객에게 제공하는 경험을 더 많이 개인화할수록
고객은 브랜드 충성도를 유지하게 된다.
browser
을 구매자로 전환하기 위해서 필요한 것이 무엇인지브랜드 업체
와 더 의미 깊은 관계를 요구하고 있다 ⭐️🙋♀️ 소비자는
🤦♀️ 고객이 자신이 주목받기를 기대했지만,
그것을 얻지 못하고 있다는 신호
⭐️⭐️⭐️
발견부분
테스트부터 마련
한다.자가진단
하도록 만든다.편한 구조가 아니라면
,기능을 추가하기 쉬운 형태로 리팩터링
하고 나서프로그램이 잘 작동하는 상황에서 그저 코드가 ‘지저분하다‘는 이유료 불평하는 것은
프로그램의 구조를 너무 미적인 기준으로만 판단하는 건 아닐까
수백줄짜리 코드를 수정할 때면,
먼저 프로그램의 작동방식을 더 쉽게 파악할 수 있도록
코드를 여러 함수와 프로그램 요소로 재구성한다.
작은 단계
로 나눠 진행한다. 버그
를 쉽게 찾을 수 있다.함수 추출 이후에는 명확하게 표현할 수 있는 간단한 방법을 찾아보자.
사람이 이해하도록 작성하는 프로그래머
가 진정한 실력자다.개인적으로 이건 잘 모르겠다.
함수 안에서 해당변수가 여러번 필요한 경우가 있는데 그때마다 호출하는거가 더 나은건지,
변수로 해서 레퍼런스만 호출하는게 좋은건지.
라고 했지만, 책 마지막에는
“특별한 경우가 아니라면 성능이슈는 일단 무시하라는 것,
리팩토링때문에 성능이 떨어진다면,
리팩터링을 마무리하고 나서 성능을 개선하자”
도착했을 때보다 깔끔하게 정돈하고 떠난다
는 규칙이 있다.작업 시작 전보다 건강하게(healthy) 만들어놓고 떠나야 한다.
얼마나 수정하기 쉬운가
다.다형성
을 활용해 계산 코드 재구성하기1 | function amountFor(aPerformance) { |
이상에 가까워지도록 리팩토링
해야한다.리팩토링을 효과적으로 하는 핵심은
DAV.
라는 별도의 XML namespace를 정의한다.공동 작업과 관련한 문제들
WebDAV는 이 문제를 개선하기 위해 잠금이라는 개념을 지원한다.
잠금이 완벽한 해결책은 아니다.
WebDAV는 2가지 형식의 잠금을 지원한다.
LOCK
, UNLOCK
을 제공한다.참고자료
RFC 4918
URL경로를 통한 가상 호스팅
포트번호를 통한 가상 호스팅
IP 주소를 통한 가상 호스팅
Host 헤더를 통한 가상 호스팅
호스트를 기준으로 리소스를 구분하는 모든 웹 서버는 HTTP/1.1을 통해 오는 리소스를 결정하려면 다음과 같은 규칙을 사용해야 한다.
HTTP 요청 메세지에
전체 URL이나 Host 둘다 없을 경우
클라에게 400 Bad Request 응답을 반환한다.
onBeforeSendHeaders
라는 콜백으로 확인 가능하다.웹 사이트에 장애가 생기는 몇가지 상황
CDN
가 될 수 있다.
기본적으로 사용자가 원격지에 있는 서버(Origin Server)로 부터 Content(예. Web Object, Video, Music, Image, Document 등)를 다운로드 받을 때 가까이 있는 서버에서 받는 것보다 시간이 오래 걸리므로, 사용자와 가까운 곳에 위치한 Cache Server에 해당 Content를 저장(캐싱)하고 Content 요청시에 Cache Server가 응답을 주는 기술입니다.
참고
CDN
의 대리 캐시 ( == 리버스 프락시 )??
CDN
의 프락시 캐시서버 팜이나 분산 크락시 캐시, 대리 서버는 혼잡을 조절하고 네트워크 트래픽을 분산시킨다.
콘텐츠를 분산시키면,
그 콘텐츠를 사용자에게 더 가깝게 만들어 주므로,
콘텐츠를 서버에서 클라로의 전송하는 시간이 단축된다.
리소스의 로딩속도를 좌우하는 요소
참고자료
]]>varient
라고 부른다.Vary
헤더를 제공한다.300 Multiple Choices
응답코드로 응답을 돌려주는 것. (상태코드 글 참고)/korean
/english
Accept
관련 헤더들을 들여다보고, 그에 알맞은 응답 헤더를 준비한다.User-Agent
헤더에 기반하여 응답을 보내줄 수도 있다.Accept
: 서버가 어떤 미디어 타입으로 보내도 되는지 알려준다.Accept-Language
: 서버가 어떤 언어로 보내도 되는지 알려준다.Accept-Charset
: 서버가 어떤 차셋으로 보내도 되는지 알려준다.Accept-Encoding
: 서버가 어떤 인코딩으로 보내도 되는지 알려준다.내용 협상 헤더들은
q
값HTTP 프로토콜은 클라가 각 선호의 카테고리마다, 여러 선택 가능한 항목을
선호도와 함께 나열할 수 있도록 품질값을 정의하였다.
1 | Accept-Language: en;q=0.5, fr;q=0.0, nl;q=1.0, tr;q=0.0 |
q는 0.0부터 1.0까지의 값을 가질 수 있다.
위 상황은 네덜란드어(nl)로 된 문서를 받기 원하고 잇으나
영어(en)로 된 문서라도 받아들일 것임을 의미한다.
때때로 서버는 클라의 선호에 대응하는 문서를 하나도 갖고있지 않을 수 도 있다.
이 경우, 서버는 클라의 선호에 맞추기 위해
문서를 고치거나 트랜스코딩 할 수 있다.
Vary
헤더를 정의한다.Vary
헤더는 캐시에게 서버가 내줄 응답의 최선의 버전을 결정하기 위해Vary
헤더를 사용한다.1 | Vary: User-Agent, Cookie |
참고자료
]]>HTTP에서 엔터티 본문이란 그저 비트들로 가득 찬 상자에 불과하다.
서버는 클라에게 문서의 문자와 언어를Content-Type charset
매개변수와Content-Language
헤더를 통해 알려준다.
클라는 서버에게
사용자가 어떤 언어를 이해할 수 있고,
어떤 알파벳의 코딩 알고리즘이 브라우저에 설치되어 있는지 말해줄 필요가 있다.Accept-Charset
과Accept-Language
헤더를 보낸다
1 | Accept-Language: fr, en;q=0.8 |
모국어를 선호하지만, 피치 못할 경우 영어도 사용하는 프랑스어 사용자가 보낸 케이스
iso-8859-1 => 서유럽 차셋 인코딩과
utf-8 유니코드 차셋 인코딩을
지원할 것이다.
q는 품질 인자로 프랑스어보다 영어에 낮은순위를 주었다. (기본은 1.0)
브라우저가 본문으로부터 225 (11100001)을 가져온 경우
á
FEH
= ف
α
BET
= ב
euc-kr과 utf-8 참고
euc-kr 방식은 원래 영어만을 고려한 1byte 길이의 ASCII 라는 인코딩 방식을 확장하여 한글을 사용할 수 있도록 만든 2byte 길이의 국가 언어 코드입니다.
국가 언어코드. 즉 우리나라에서만 쓸 수 있도록 만든 코드이며 세계 어디에서나 공통으로 사용되는 인코딩 방식이 아니기 때문에, 다른 언어를 사용하는 환경(외국 등)에서는 한글 페이지를 제대로 볼 수 없는 문제가 발생합니다.
이를 해결하기 위해 새로운 인코딩 방식이 개발되었는데, 그중 가장 보편화된 인코딩이 UTF-8입니다. (3byte)
예전에는 용량이 작은 euc-kr 방식을 선호하는 곳들도 많았으나, 현재는 용량 문제보다 표준화 및 글로벌 환경을 고려해야 하므로 UTF-8 인코딩 방식을 강력하게 권고하는 바입니다.
웹 서버는 클라에게 MIME charset 태그를 charset 매개변수와 함께 Content-Type 헤더에 담아 보낸다.
1 | Content-Type: text/html; charset=utf-8 |
만약 나열되지 않았다면, 수신자는 문서의 콘텐츠로부터 문자집합을 추측하려고 시도한다.
받은 HTML 파일에서 meto
태그중 HTTP-EQUIV
라는 속성을 갖고 있는 태그를 찾는다.
1 | <meta |
만약 문서가 html이 아니라면, 혹은
meta Content-Type 태그가 없다면,
소프트웨어는 언어와 인코딩에 대한 일반적인 패턴을 찾기 위해 실제 텍스트를 스케닝하여 문자 인코딩을 추측한다.
클라가 문자 인코딩을 추측하지 못했다면 iso-8859-1
인것으로 가정한다.
1 | Accept-Charset: iso-8859-1, utf-8 |
ESC ( B
, ESC ( J
, ESC $ @
, ESC $ B
)은 한 집합에서 다른 집합으로 전환시켜준다. (모달)Content-Language 헤더
Accept-Lanugage 헤더
언어 태그의 종류 ([RFC 3066] 기준)
es
(스페인어)en-GB
(영국 영어)no-bok
(노르웨이어의 Book Language를 의미)sgn-US-MA
(마서스 비니어드 섬의 수화)i-navajo
)x-snowboarder-slang
(스노우보드 타는 사람..)서브태그
sgn-US-MA
첫번째 서브태그 : 이름공간
i
라면, IANA에 등록된 것x
라면, 특정 개인이나 집단 전용의 비표준 확장 서브태그다.두번째 서비태그: 이름공간
나머지 서브태그: 이름공간
-
_
.
!
~
*
'
(
)
;
/
?
:
@
&
=
+
$
,
%
<HEX>
<HEX>
스페이스 (아스키 32): %20 (20은 32의 16진법 표현이다.)%
(아스키 25): %25encodeURIComponent
메서드를 사용하면 URI 인코딩을 진행할 수 있다.)ESC ( J
를 삽입할 수 있으며 ESC ( B
로 다시 아스키로 돌아올 수 있다.한글.com
=> xn--bj0bj06e.com
)참고자료
]]>Expires
Cache-Control
If-Modified-Since: 날짜
If-Modified-Since
: Last-Modified
- 변한게 있으면 보내달라If-Unmodified-Since
: Last-Modified
- 변한게 없으면 보내달라If-Match
: ETag
- 같으면 보내달라If-None-Match
: ETag
- 다르면 보내달라W/
를 붙임으로써 약한 엔터티 태그임을 알릴 수도 있다.클라가 문서의 일부분이나 특정 범위만 요청할 수 있도록 해준다.
범위요청을 이용하면, HTTP 클라는 받다가 실패한 엔터티를 일부 혹은 범위로 요청함으로써, 다운로드를 중단된 시점에서 재개할 수 있다.
1 | Range: bytes=4000- |
모든 서버가 범위 요청을 맏아들일 수 있는 것은 아니지만, 많은 경우 가능하다.
Accept-Range
헤더를 포함시키는 방법으로 알려줄 수 있다.
1 | Accept-Ranges: bytes |
참고자료
]]>HTTP는 매일 수십억 개의 미디어 객체를 실어 나른다.
HTTP는 콘텐츠를 잘 나르기 위한
잘 라벨링된 엔터티를 사용한다.
Allow
: 이 리소스에 대해 어떤 요청 메서드가 허용되는지Content-Type
: 엔터티에 의해 전달된 객체의 종류Content-Length
: 전달되는 메세지의 길이나 크기Content-Language
: 전달되는 객체와 가장 잘 대응되는 자연어Content-Encoding
: 객체 데이터에 대해 행해진 변형 (압축 등)Content-Location
: 요청 시점 기준으로, 객체의 또 다르 위치Content-Range
: 이 엔터티가 부분 엔터티라면, 이 헤더는 이 엔터티가 전체에서 어느 부분에 해당하는지 정의한다.Content-MD5
: 엔터티 본문의 콘텐츠에 대한 체크섬(중복검사의 한 형태)Last-Modified
: 서버에서 이 콘텐츠가 생성 혹은 수정된 날Expires
: 이 엔터티 데이터가 더 이상 신선하지 않은 것으로 간주되기 시작하는 날짜와 시각ETag
: 이 인스턴스에 대한 고유한 검사기Content-Length
엔터티의 길이switch (true)
HEAD
메서드IANA: 인터넷 할당 번호 관리기관 Internet Assigned Numbers Authority
Content-Type: text/html; charset=iso-8859-7
multipart/form-data
1 | Content-Type: multipart/form-data; boundary=[abcdefghijklmnopqrstuvwzyz] |
multipart/byteranges
Content-MD5
Content-MD5 헤더는 그다지 자주 전송되지 않는다.
Content-Encoding
모던 브라우저에는 gzip 압축해제를 자동으로 해준다. 참고
Content-Encoding: {유형}
1 | Accept-Encoding: compress, gzip |
Transfer-encoding
Transfer-encoding
헤더Q
값을 가질 수 있다.1 | GET /new_products.html HTTP/1.1 |
1 | HTTP/1.1 200 OK |
Transfer-encoding
TE
지속커넥션에서는, 본문을 쓰기 전에 만드시 Content-Length 헤더에 본문의 길이를 담아서 보내줘야 한다.
청크 인코딩은 서버가 본문을 여러 청크로 쪼개 보낼 수 있게 해줌으로써
청크 인코딩은
<CR><LF>
로 분리된다.1 | 27<CR><LF> |
1 | 0<CR><LF> |
클라 또한 청크 인코딩된 데이터를 서버로 전송한다.
TE
헤더가 트레일러를 받아들일 수 있음을 나타내고 있는 경우메세지 시작 시점에서 그 값을 알 수 없는 추가적인 헤더 필드를 담을 수 있다.
Content-MD5
헤더가 있다.Transfer-Encoding
, Trailer
, Content-Length
를 제외한 어떤 HTTP 헤더도 트레일러로 보낼 수 있다.참고자료
]]>2019 상반기 회고 + 하반기 다짐 (feat. 글또) ➔
상반기 때는 기본 실력의 범위에 대해서만 재정의하였고, 깊이 있는 공부를 진행하지 못했었다. 깊이 있는 공부란.. 깊이 파보기도 하고, 실습도 하고 이론 정리도 하는 것을 생각하는데, 상반기 때는 “이것도 공부해야 하는구나”라는 식의 공부할 거리 알아보고 우선순위 정하기 정도만 진행했었다.
이에 중간 정산 시에 문제 인지를 하여서, 하반기 때는 구체적인 action plan을 그려보았는데,
첫째는 웹 네트워크 공부, 두 번째는 기본 공부로써 구글 웹 문서와 mdn 전체 훑어보기를 세웠었다.
2019 하반기 뭘 해볼까 (목표 설정) ➔
프론트 개발자가 인지할 수 있는 웬만한 네트워크 이슈는 먼저 인지하고 디버킹하고 싶어서 웹 네트워크 지식은 한번 쭉 정리해보고 싶었다. 팀장님이 추천해주신 ‘http 완벽가이드’라는 책을 선택하였다. 제발 책 전체를 다 읽고 싶었는데, 지금까지 경험상 절대 혼자서는 완주를 못 할 것이라는 생각이 들어서, 주변에 같이 스터디할 사람을 찾아보았다.
스터디를 모집하는 이슈도 있었지만, 운영에 대한 고민도 있었다.
보통의 스터디는 장기 기억을 위해서
개인적으로 발표 준비라는 것은 콘텐츠 제작과 + 발표라는 2가지 전달 방법을 만들어야 하고,
이는 스터디를 부담스럽게 만드는 요인이라고 생각이 들었다.
발표로 진행하는 스터디는 장기기억을 위해서
이를 대체하는 방법이 무엇일까 고민했을 때
TIL 수준보다 좀 더 읽는 이를 고려야 하는 블로그 글을 정리 매개체로 하고,
블로그 글 자체를 콘텐츠를 만드는 수준으로 끌어올려서 글을 작성하게 하면
린한 기획이 선행되어야 하기 때문에 기억에 오래 남지 않을까 하여,
해당 방식의 글 작성 조건으로 모집 글을 작성하였다.
또한, 다른 사람의 글을 첨삭해주면서 글을 몇 번이라도 더 복습하며 볼 수 있다고 생각하여
짝궁 리뷰도 필수로 하게끔 진행하였는데,
진행해보니 ‘글을 읽어서 학습하며 첨삭한다’가 아니라 주객이 전도되는 상황이 벌어져서,
다음에는 리뷰하는 것은 제외하였다.
현재 상황을 봤을 때는, 콘텐츠 같은 정리 글을 쓴다기보다는 글에 있는 내용을 요약정리하는 수준으로 되었지만, 정리에서 오는 학습효과 정도는 가져갈 수 있었던 것 같다.
상반기 때는 디자인 시스템을 적용하기 전에 팀원들에게
디자인 시스템이 어떤 생산성을 주는지에 대해 알리기 위해 사내 발표를 진행했었다.
사내 발표 때 디자인시스템의 기본 구조를 아토믹 패턴 개념을 기반으로 설명했었는데,
발표 피드백으로 어느 수준까지 쪼개야 하는지에 대해서 잘 모르겠다는 의견이 나왔고 이점을 보완하여서 개념을 재정리하였다.
그러던 중에 감사하게도 GDG-devfest 발표기회가 찾아와서 정리한 부분을 발표하게 되었다.
(발표 회고 글도 작성해야 하는데 언제 하지 8ㅅ8)
발표자들의 이해를 돕기 위해서 실제로 적용하는 예시까지 정리해드렸는데,
이때 스스로 다시 한번 개념에 대해서 정리하게 되었고, 이를 바탕으로 회사 프로젝트의 구조도 수정할 수 있게 되었다.
확실히 연필 놓고 멀리서 바라보는 시간은 중요한 듯하다.
으… 포트폴리오 작업은 이번에도 이루지 못했다.
헥소 블로그 테마 만들기라도 하자고 action plan을 잡았었는데, 진행하지 못했다.
아무래도 공부하는 것을 더 우선순위로 잡아놔서 개인 포폴작업용으로 개발하는 것은 우선순위가 내려간 듯하다.
회사 업무와 관련된 토이프로젝트를 만들 생각으로 다시 접근해야겠다는 생각이 들었다.
글또는 예치금을 걸어두고 2주마다 블로그 글을 작성하는 모임이다.
상반기 글또2기 마무리에 이어서 3기도 참여하게 되었다. 이번 기수에는 회사 팀원들도 함께 참여하였다!
http완벽가이드 스터디와 스터디원도 겹치고, 일정도 겹치는 상황이라,
거의 스터디 글을 올리곤 했어서 다양한 글을 작성하지 못해서 아쉬웠다.
역시 글 작성은 일주일에 2개는 무리인듯하다..
그래도 스터디 글이 아닌 주제로 작성했던 글들이
평소에 작성하고 싶었던 글 목록에 있던 글들이라, 작성할 때 만큼은 재미있었다.
이번 기수에는 포지션끼리 그룹핑하여 피드백하는 방식이어서
네트워킹도 되고 기술공유도 되어서 유익하였다.
4기도 해야지! 끝까지 해서 고인물이 되어야겠다.
기록하며 성장하기라는 주제로 개인 성장기? 공부 방법 등을 공유해 드렸다. ➔
취준생분들이 많이 오셔서 도움이 되셨다는 피드백을 많이 주셨다. 🙏
발표에 대한 경험담과 준비 과정은 따로 글로 작성하려고 한다.
요약하자면 처음 하는 대규모 발표였기 때문에 정신이 혼미했었다..는 것..
생각보다 발표를 듣고 긍정적인 피드백을 주신 분들이 많으셨다.
개인적으로 아토믹 패턴 기반은 아니더라도
디자인 시스템은 업무의 생산성과 프로덕트 브랜딩을 위해서
다른 회사들에도 꼭 적용되면 좋겠다는 생각이 들어서,
해당 개념이 한 사람이라도 더 알게 하는 데에 기여를 했다는 것에 의미를 두었다. 🙏
좋아하는 코드 스피츠 강의를 1개 참여했다.
하반기 때는 너무 코드스피츠 이론 수업에 매달리지 말고 복습이나 실습을 좀 해야겠다는 생각 때문에 다른 강의는 참여하지 않았다 (못했다..는 아니다.) 그러다 강남에서 열린다는 소문을 듣고 +_+ 부랴부랴 신청하게 되었다.(ㅎ.ㅎ)
강의장에서 http 완벽가이드 스터디원들도 오프라인에서 얼굴도 한 번씩 뵙기도 했다.
이번 강의는 3회 강의가 정말 알참 of 알참이었는데 알참을 넘어서 나에게는 overflow한 개념이었다.
그래도 제너레이터를 왜 사용해야 하는지, 넌블럭킹에 대한 개념 등을 알 수 있어서 좋긴 했지만
아직 3개의 강의를 복습하지 못했다.. 올해 가기 전에 해야 하눈데!! ㅠ
저번 회고 글에서도 작성했지만, 실습 위주로 복습해야 진짜 내 것이 될 텐데
자꾸 코드스피츠 수업은 그것을 못 하게 된다ㅠ 리소스 부족도 사치겠지.. 복습하고 꼬옥 실습을 진행하자.
단기목표
패스트 캠퍼스의 웹 프로그래밍 스쿨 모의 면접관 제안이 들어와서 10월부터 12월까지 진행하게 되었다.
예전 공부했을 때 생각도 나고, 취준했을 때도 생각나서 나름 열심히? 상담 + 모의 면접을 진행하였다.
단기간에 학습하느라 힘드실 텐데, 다들 열의도 넘치시고 그 뭐랄까 열정!!이 느껴져서 어떻게든 더 많이 알려드리려고 노력했다.
이번 연도에는 실무에서 겪은 것으로 공부하고, 같이 공부하는 스터디 참여, 개발 외적인 부분도 공부하려고 하였다. 확실히 이론 공부보다 실무에서 필요한 공부 위주로 방향을 잡아 공부하니 학습속도가 개인 공부 때보다는 빠른듯하다. 개발 이외의 공부를 해도 좋으나 개발 공부를 소홀히 하지 않는 선에서 진행해야겠다. (라고했지만, 그렇게 되면 속도가 느려져서 답답하다.)
두꺼운 책은 부담스러워서 항상 완주하지 못했었는데, 위 스터디 방식대로 진행하고, 현재 완주가 눈앞에 보이니, 앞으로 두꺼운 책 공부는 이런 식으로 공부하면 되겠다 싶다.
글 갯수는 중요하지 않지만!! 너무 한쪽 방향으로만 글을 쓰면 좋지 않으니까.
하반기에 어떤 글을 썼는지 알아보고 다시 계획을 잡아보자.
2기 때 글의 카테고리를 이렇게 정리했었다.
2기 때 잡은 카테고리를 기준으로 3기 때는 1번 5개/ 2번 3개/ 3번 2개/ 4번 2개 작성을 목표로 잡았었다.
😅 이번에는 1번에 굉장히 쏠려버렸다.
삽질한 업무들이 많아서 개인적으로 글감을 정리하고 있었는데,
너무 스터디 글만 올리는 것 같다고 인지될 때마다 글감에서 꺼내서 작성하였다.
그나마 2개..ㅎㅎ 세미나 다녀와서 글 쓰는 건.. 정말 손에 안 잡히나보다 😂😂
HTML 컨퍼런스랑 구글 SEO는 작성해야 하는데 :(
스터디 끝나면 글감에 있는 글 하나씩 꺼내서 작성하자!
2019년도에는 대부분의 목표달성 계획에 추상적이고 모호하게 잡았던 듯하다.
물론 지금 이렇게 계획한다고 해서! 100% 지키면 나는 로봇이겠지만.. 최대한 계획한 것을 지키면서 지내보자.
장기목표: 2020년도에 하고 싶은 내용
단기목표: 2020년도 상반기에 하고 싶은 내용
최근 인증서 관련 이슈를 만난적이 있었는데,
이번 장을 통해서 조금이나마 이해가 될 수 있게 되었다 :)
보안 HTTP는 선택적이다.
웹 서버로의 요청을 만들때, 웹서버에게 HTTP의 보안 프로토콜 버전을 수행한다고 말해줄 방법이 필요하다.
이것은 URL의 스킴을 통해 이루어진다.
1 | https://feel5ny.github.io |
만약 URL이 http 스킴을 갖고 있다면
클라는 서버에 80번 포트로 연결하고
평범한 HTTP 명령을 전송한다.
만약 URL이 https
스킴을 갖고 있다면
클라는 서버에 443번 포트로 연결하고
서버와 바이너리 포맷으로 된 몇몇 SSL 보안 매개변수를 교환하면서
핸드셰이크를 하고,
암호화된 HTTP 명령이 뒤를 잇는다.
SSL 트래픽은 바이너리 프로토콜이기 때문에 HTTP와는 완전히 다르다.
HTTP에서는 클라는
HTTPS에서는 클라는
실제로 좀더 자세히 보면..
www.bing.com에 접속할 때 SSL 핸드쉐이크 과정을 와이어 샤크를 보면서 알아보자.
온라인 인증서 상태 프로토콜
의 약자로, 인증서 유효성 확인을 제공하는 방법이다.ECDHE : Elliptic Curve 및 Ephermeral 을 지원하는 디피 헬만 (Diffie Hellman) 방식 (PFS, Perfect Foward Secrecy 지원) 출처
X.509 v3
에서 파생되 인증서이다. 디지털 인증서CA
= Certificate Authority브라우저마다 다르게 셋팅되어있다. 출처
서버가 누군가 다른 이의 인증서를 복사하거나,
그들의 트래픽을 가로채는 것을 방지하기 위해,
대부분의 브라우저는
인증서의 도메인 이름이
대화 중인 서버의 도메인 이름과 비교하여 맞는지 검사한다.
서버 인증서에는 보통 단일 도메인 이름이 들어있지만
몇몇 CA는 서버 클러스터나 서버 팜을 위해
서버 이름의 목록이나 서버 이름들에 대한 와일드카드 표현이 들어있는 인증서를 만든다.
서버 클러스터란? (IT솔루션 by 올파)
- 서버 클러스터란 각기 다른 서버(Server Enterprise or server Datacenter)들을 하나로 묶어서 하나의 시스템같이 동작하게 함으로써, 클라이언트들에게 고가용성의 서비스를 제공하는것을 말한다.
- 클러스터로 묶인 한시스템에 장애가 발생하면, 정보의 제공 포인트는 클러스터로 묶인 다른 정상적인 서버로 이동한다.
- 서버클러스터는 사용자로 하여금 서버 기반 정보를 지속적이고, 끊기지않게 제공받을수 있게 한다
서버 팜이란?
- 서버 클러스터라고 불리기도 하는 서버팜은 컴퓨터 서버와 운영 시설을 한곳에 모아 놓은 곳
- 허가받지 않은 외부에선 접근이 불가능
- 임의의 서버가 중단되더라도 다른 서버로 대체되어 원할한 서비스를 제공한다.
와일드 카드란?
- 파일을 지정할 때, 구체적인 이름 대신에 여러 파일을 동시에 지정할 목적으로 사용하는 특수 기호.
*',?'
따위.
만약 호스트명이 인증서의 신원과 맞지 않는다면,
사용자를 우선으로 생각하는 클라이언트는 반드시 이 사실을 사용자에게 알리거나 잘못된 인증서 에러와 함께 커넥션을 끊어야 한다.
잘 모르겠다.
OpenSSL
)clients1.online.msdw.com 의 사이트라고 가정
SSL 컨텍스트가 초기화 되었다.
clients1.online.msdw.com의 IP주소: 63.151.15.11
호스트 clients1.online.msdw.com, 포트 443으로 TCP 커넥션을 열었다.
SSL endpoint가 생성되었으며 핸드셰이크 완료
다음의 암호로 SSL 연결이 됨: DES-CBC3-MD5
서버 인증서를 받았다.
1 | 대상: /C=US/ST=Utah/L=Salt Lake City/O=Morgan Stanley/OU=Online/CN=clients1.online.msdw.com |
암호화된 채널을 통해 HTTP 요청을 보냈다.
1 | GET / HTTP/1.0 |
HTTP응답에서 615바이트를 가져왔다.
1 | HTTP/1.1 302 Found |
모두 끝났으므로 커넥션을 닫고 정리한다.
클라는 종종 웹 프락시 서버를 이용한다.
그러나 클라가 서버로 보낼 데이터를 서버의 공개키로 암호화하기 시작했다면, 프락시는 더 이상 HTTP 헤더를 읽을 수 없다.
만약 프락시가 HTTP 헤더를 읽을 수 없다면, 요청을 어디로 보내야 하는지 알 수 없게 된다.
해결 방법 중에 인기있는 방법은 HTTPS SSL 터널링 프로토콜이다.
클라는 먼저 프락시에게 자신이 연결하고자 하는 안전한 호스트와 포트를 말해준다.
클라는 이 내용을 프락시가 읽을 수 있도록 암호화가 시작되기 전의 평문으로 말해준다.
HTTP는 CONNECT라 불리는 새로운 확장 메서드를 이용해서 평문으로 된 endpoint 정보를 전송하기 위해 사용된다.
1 | CONNECT home.netscape.com:443 HTTP/1.0 |
클라는 프락시로부터의 응답을 기다릴 것이다.
200 Connection Established
참고자료
]]>최근 인증서 관련 이슈를 만난적이 있었는데,
이번 장을 통해서 조금이나마 이해가 될 수 있게 되었다 :)
다음을 제공해 줄 수 있는 HTTP 보안 기술이 필요하다.
편재성은 자원을 뜻할때 주로 쓰이는 성질이다.
자원의 민족주의. 도처에 존재하는 성질이라고 이해하면 됨
S
S
는 Over Secure Socket Layer의 약자이다.암호법 cryptography는 메세지 인코딩과 디코딩에 대한 과학이자 기술이다.
텍스트, 평문
: 인코딩 되기 전의 원본 메세지암호문
: 암호가 적용되어 코딩된 메세지P
, 인코딩 함수 E
, 디지털 인코딩 키 e
가 주어지면 부호화된 암호문 C
를 생성할 수 있다.C
를 디코더 함수 D
와 디코딩 키 d
를 사용해서 원래의 평문 P
로 도로 디코딩할 수 있다.1 | C = E(P,e) |
1 | echo 'this is the plain text' > plaintext.txt; |
-in
) 내용들을 des3방식으로 암호화를 하고, ciphertext.bin이라는 파일로 산출할(-out
) 것이다 라는 뜻.대칭키
!이런식으로 암호화된다.
1 | openssl enc -d -des3 -in ciphertext.bin -out plaintext2.txt; |
-d
) 하여서 plaintext2.txt 파일에 산출할 것이다 라는 뜻.노드A가 노드B에게 메세지를 보내고, 그것을 서명하는 전체 플로우.
X.509
v3 인증서X.509
라 불리는 표준화된 서식에 그들의 정보를 저장하고 있다는 것이다.X.509
인증서 표준을 기반으로 한다.X.509
기반 인증서에는X.509
v3 인증서는X.509
인증서 버전의 번호 (보통은 v3)참고자료
]]>점점 번역이 이해하기 더 어려워질 정도로 직역형태다..
qop
: 가장 강력한 인증 매커니즘 선택하기400 Bad Request
must-revalidate
나 public
qop
400 Bad Request
영역 값은, 접근한 서버의 루트 URL과 결합하여, 보호 공간을 정의한다.
영역은 보호 영역의 집합으로 분할할 수 있도록 해준다. (보호 영역으로 따로 구분해둔다..)
번역이해가 어려워서 나름 위 문장대로 이해함..
원문: 영역은 서버의 보호된 리소스들을 자신만의 인증제도와 인가 데이터베이스 어느 한쪽 혹은 양쪽 모두를 가진 보호 영역의 집합으로 분할 할 수 있도록 해준다.
영역의 값은 일반적으로 원 서버에 의해 할당되는 문자열이다.
(인증 제도에 추가적인 의미를 더한다.)
보호공간은 어떤 자격이 자동으로 적용되는 영역을 결정한다.
보호공간의 구체적인 계산은 인증 메커니즘에 달려있다.
WWW-Authenticate: domain
필드는1 | domain = "'/cart' '/main'" |
이 domain 목록의 모든 URI와
논리적으로 그 하위에 위치한 모든 URI는
같은 보호 공간에 있는 것으로 가정한다.
만약 domain 필드가 없거나 빈 값이라면,
인증을 요구하는 서버의 모든 URI는 그 보호 공간에 있는 것이다.
%
escape 형식으로 대체될 수 있다.must-revalidate
나 public
중 하나가 응답에 존재하지 않는 한must-revalidate
Cache-Control 지시자를 포함한 경우, public
Cache-Control 지시자를 포함한 경우,헤더 부당 변경
재전송 공격
다중 인증 메커니즘
사전 공격 dictionary
악의적인 프락시와 중간 공격 Man in the Middle Attack
리다이렉션 기술과 차단 프락시의 도입으로 사용자는 그의 요청이 프락시를 통과한다는 것조차 눈치 채지 못하고 한다.
만약 이들 프락시 중 하나가 악의적이거나 보안이 허술하다면,
클라는 중간자 공격에 취약한 상태가 될 가능성이 있다.
해결할 좋은 방법은 없지만, 가능한 해결책은,
등이 있다.
공격을 방어하는 제일 좋은 방법은 SSL을 사용하는 것이다.
선택 평문 공격
비밀번호 저장
참고자료
]]>자세히…….
LDAP, CRAM-MD5
MD5 해쉬의 경우에는 특히나 Dictionary Attack에 취약한데,
Dictionary Attack이란, Hash된 값과 원래 값을 Dictionary (사전) 데이터 베이스로 유지해놓고, Hash 값으로 원본 메시지를 검색하는 방식
(출처: 조대협의 블로그)
fingerprint
혹은 요약 digest
을 보낸다.MD5: 메세지 다이제스트 #5의 약어
SHA 보안 해시 알고리즘: 다른 다이제스트 함수
WWW-Authenticate
인증요구에 담겨서 서버에서 클라로 넘겨진다.WWW-Authenticate
인증요구 메세지에 담아,다이제스트 인증의 핵심은
값을 조합한 단방향 요약이다.
RFC7616 2617
요약은 다음 3가지 요소로부터 계산된다.
A1, A2 두 조각의 데이터는 요약을 생성하기 위해 H와 KD에 의해 처리됨
A1 데이터에는
사용자 이름 / 비밀번호 / 보호 영역 / 난스가 포함된다.
“<알고리즘>”인 경우 (예 : “SHA-256”),
A1은 사용자 이름, 영역, 비밀번호를 콜론으로 연결한 것이다.
1 | A1 = <사용자>:<영역>:<비밀번호> |
<알고리즘> -sess
인 경우 (예 : “SHA-256-sess”),
A1은 서버의 인증 요청에 제공된 nonce 값과 다음 클라이언트 요청의 cnonce 값을 사용하여 계산됩니다
1 | A1 = H( unq(username) ":" unq(realm) ":" passwd ) |
A2 데이터에는 메세지 자체의 정보를 나타냄
URL / 요청메서드 / 메세지 엔터티 본문
메서드, 리소스, 메세지의 위조를 방지하기 위해 사용됨
RFC7616 2617은 선택된 보호 수준 (quality of protection, qop)에 따른
A2의 두가지 사용법을 정의하고 있다.
HTTP 요청 메서드와 URL만 포함하는 것이다.
이것은 기본값이기도한 qop=”auth”일 때 사용된다.
1 | A2 = Method ":" request-uri |
메세지 무결성 검사를 제공하기 위해 메세지 엔터티 본문을 추가하는 것
qop=”auth-init”일 때 사용된다.
1 | A2 = Method ":" request-uri ":" H(entity-body) |
1 | // 개인적으로 빠른 인지를 위해 자바스크립트 문법 사용 |
RFC7616 2617은 주어진 H, KD, A1, A2로 요약을 계산하는 방법에는,
난스 횟수 집계(nc) 및 대칭 인증의 지원(qop)을 포함한다.
1 | response = <"> < KD ( H(A1), unq(nonce) |
WWW-Authenticate
인증요구에 대한 클라 응답은,WWW-Authenticate
인증요구를 받을 때까지 지속된다.WWW-Authenticate
에 stale=true
로 정의함으로써,브라우저는 흔히 사용자 이름과 비밀번호 들에 대한 클라 측 데이터베이스를 관리한다.
사용자가 어떤 사이트에 한번 인증을 하면,
브라우저는 흔히 그 URL에 대한 다음번 요청 때 올바른 Authorization 헤더를 전송한다.
다이제스트 인증에서 사전 인가는 약간 더 복잡한데,
왜냐하면 난스 기술은 재전송 공격을 저지하기 위한 것이기 때문에다.
서버는 임의의 난스를 생성하기 때문에,
인증요구를 받기 전에는 클라가 무엇이 올바른 Authorization 헤더인지 알 방법이 없다.
다이제스트 인증은 여러 안전한 기능을 유지하면서 사전 인가를 할 수 있는 몇 가지 방법을 제안한다.
클라가 새 WWW-Authenticate
인증요구를 기다리지 않고 올바른 난스를 취득할 수 있는 방법이 몇가지 있다.
Authentication-Info
성공 헤더에 담아서 미리 보낸다.서버는 Authentication-Info
성공헤더를 통해 다음 난스 값을 미리 제공할 수 있다.
1 | Authentication-Info: nextnonce="<난스 값>" |
주어진 다음 난스로 클라는 Authorization 헤더를 미리 만들어 둘 수 있다.
WWW-Authenticate
에 stale=true
로 정의)난스의 내용은 불투명하고 구현 의존적이다.
1 | // RFC 7616 기준 |
타임스탬프는 서버에서 생성된 시간 혹은 아무것이나 반복 불가능한 값이면 된다.
ETag는 요청된 엔터티에 대한 ETag 헤더값
비밀 데이터는 서버만 알고 있는 데이터
서버는 클라 인증 헤더를 받은 뒤,
위 공식에서 해시 부분을 재계산 해보고 클라 인증 헤더의 난스와 일치하지 않거나 타임스탬프가 오래되었다면, 요청을 거절한다.
재전송 공격을 방지하기 위해, 어떤 구현은 이전에 사용된 난스나 요약을 받아들이지 않도록 결정할 수 있다.
혹은 POST나 PUT 요청을 위해 일회성 난스나 요약을 사용하고
GET 요청을 위해 타임스탬프를 사용할 수도 있다.
참고자료
]]>HTTP는 필요에 따라 고쳐 쓸 수 있는 제어 헤더를 통해,
다른 인증 프로토콜에 맞추어 확장할 수 있는 프레임워크를 제공한다.
HTTP에는
이라는 두가지 공식적인 인증 프로토콜이 있다.
미래에는, 사람들이 HTTP 인증요구/응답 프레임워크를 사용해 새로운 프로토콜을 고안해 낼 수 있을 것이다.
현대에 HTTP의 인증요구/응답 프로토콜을 사용하는 인증 프로토콜로는 OAuth가 있다.
OAuth는 모바일 기기같은 다양한 어플리케이션에서 API 인증을 위해 사용하는 최신 인증 프로토콜이다. (RFC6749)
401
과 함께 요청 반려. WWW-Authenticate
헤더에 해당 영역을 설명해 놓는다.Authorization
헤더를 함께 보냄1 | WWW-Authenticate: Basic realm="Access to the staging site" |
realm
그룹으로 나눈다.:
으로 이어서 합치고,중개 프락시 서버를 통해 인증할 수도 있다.
프락시 서버에서 접근 정책을 중앙 관리할 수 있는 장점이 있음
상태코드: 407
Proxy-Authenticate (like WWW-Authenticate
)
Proxy-Authorization (like Authorization
)
메세지의 인증헤더를 건드리지는 않지만,
그 외 다른 부분을 수정해서 트랜잭션의 본래 의도를 바꿔버리는
프락시나 중개자가 중간에 개입하는 경우,
기본 인증은 정상적인 동작을 보장하지 않는다.
기본인증은 다른 사람들이 보지 않기를 원하긴 하지만,
보더라도 치명적이지 않은 경우에는 여전히 유용하다.
기본 인증보다 더 복잡하고 강력한 보안 관련 속성인 다이제스트 인증을 다음 포스팅에서 알아보자.
참고자료
]]>Discard
파라미터가 설정되어 있거나,Expires
, Max-Age
같은 파기되기까지의 남은 시간을 표현하는 파라미터가 없으면 세션 쿠키가 된다.이름=값
형태의 리스트를 가지고,Set-Cookie
혹은 Set-Cookie2
같은 HTTP응답 헤더에 기술되어 사용자에게 전달한다. 참고
Set-Cookie2
은 더 이상 사용되지 않는다.
많은 웹 사이트는 광고를 관리하는 협력업체와 계약을 한다. (third-party 쿠키)
- 이 광고들은 웹사이트 자체의 일부인 것처럼 제작되고, 지속 쿠키를 만들어낸다.
- 같은 광고사에서 제공하는 서로 다른 웹사이트에 사용자가 방문하면,
브라우저는 앞서 만든 지속 쿠키를 다시 광고사 서버로 전송한다.- 광고사는 이 기술에
Referer
헤더를 접목하여,
사용자의 프로필과 웹사이트를 사용하는 습관에 대한 방대한 데이터를 구축할 수 있다.
아래 브라우저에 저장되어 있던 쿠키 내용을 해당 도메인과 같을 경우
요청 헤더의 Cookie에 포함시킨다.
/search
/search
여기에만 해당하는 쿠키!;
으로 이어 기술한다.이름=값
: 필수 값Expires
: 선택적인 속성. 쿠키의 생명주기를 가리키는 날짜 문자열Domain
: 선택적인 속성. 브라우저는 이 속성에 기술된 도메인을 사용하는 서버 호스트명으로만 쿠키를 전송한다.Path
: 선택적인 속성. 서버에 있는 특정 문서에만 쿠키를 할당할 수 있다./foo
경로는 /foobar
와 /foo/bar.html
에 들어맞는다./
는 모든 것에 들어맞는다.Secure
: 선택적인 속성. 쿠키는 HTTP가 SSL 보안 연결을 사용할 때만 쿠키를 전송한다.HttpOnly
: HttpOnly는 쿠키의 범위를 HTTP 요청으로 제한한다.쿠키 버전 1은 RFC 2109를 뜻한다.
RFC 2109는 기존 넷스케이프 쿠키의 스펙을 체계적으로 정리하고 수정하려고 시도한 것
Version0 쿠키 속성은 Name, Value, Expires, Domain, Path, Securer가 있다.
Version1 쿠키 속성은 Name, Value, Comment, Domain, Max-Age, Path, Secure, Version이 있다.
Set-Cookie2와 Cookie2 헤더는 더 이상 사용되지 않으므로 패스
Amazon.com의 예를 통해 살펴보자.
브라우저가 Amazon.com의 루트 페이지를 처음 요청한다
1 | GET / HTTP/1.0 |
서버는 클라를 전자상거래 소프트웨어 URL로 리다이렉트 시킨다.
1 | HTTP/1.1 302 Found |
클라는 리다이렉트 URL로 요청 보낸다.
1 | GET /exec/abidos/subst/home/redirect.html HTTP/1.0 302 Found |
서버는 응답에
두 개의 세션 쿠키를 기술하고 (Set-Cookie
= 요 쿠키 브라우저에 넣어두세요)
사용자를 다른 URL로 리다이렉트 시키며
클라는 다시 이 쿠키들을 첨부하여 요청을 보낸다.(Cookie
)새로운 URL(http://www.amazon.com/exec/abidos/subst/home/redirect.html/002-1135265-8016838)은 자체에 상태 정보를 갖고 있으므로 = 뚱뚱한 URL
1 | HTTP/1.1 302 Found |
클라는 새로운 URL을 요청을 요청받았던 두 개의 쿠키와 함께 보낸다.
1 | GET /exec/abidos/subst/home/redirect.html/002-1135265-8016838 HTTP/1.0 |
서버는 home.html 페이지로 리다이렉트 시키고, 쿠키 두 개를 더 첨부한다.
1 | HTTP/1.1 302 Found |
클라는 home.html 페이지를 가져오고, 총 4개의 쿠키를 전달한다.
1 | GET /exec/abidos/subst/home/home.html/002-1135265-8016838 HTTP/1.0 |
서버는 콘텐츠를 보낸다.
쿠팡 첫 화면 진입 시 진행되는
광고 솔루션 크리테오 세션 추적 과정 중 일부
캐시 되지 말아야 할 문서가 있다면 표시하라Control: no-cache="Set-Cookie"
Set-Cookie 해더를 캐시 하는 것에 유의하라
1 | Cache-Control: must-revalidate, max-age=0 |
Cookie 헤더를 가지고 있는 요청을 주의하라
참고자료
]]>From
(요창): 사용자 이메일 주소User-Agent
(요청): 사용자의 브라우저Referer
(요청): 사용자가 현재 링크를 타고 온 근원 페이지From
User-Agent
Referer
Client-ip
나 X-Forwarded-For
같은 확장 헤더를 추가하여 이 문제를 해결하려 했다.X-Forwarded-For
HTTP 프록시나 로드 밸런서를 통해 웹 서버에 접속하는 클라이언트의 원 IP 주소를 식별하는 사실상의 표준 헤더다.
웹 서버는 사용자 이름과 비밀번호로 인증할 것을 요구해서, 사용자에게 명시적으로 식별 요청을 할 수 있다.
웹 사이트 로그인이 더 쉽도록 WWW-Authenticate
와 Authorization
헤더를 사용해 웹 사이트에 사용자 이름이 전달하는 자체적인 체계를 가지고 있다.
- WWW-Authenticate
- Authorization
HTTP Authorization 요청 헤더는 서버의 사용자 에이전트임을 증명하는 자격을 포함하여, 보통 서버에서 401 Unauthorized 상태를 WWW-Authenticate 헤더로 알려준 이후에 나옵니다.
한번 로그인하면, 브라우저는 사이트로 보내는 모든 요청에 이 로그인 정보를 함께 보내므로, 웹서버느 그 로그인 정보는 항상 확인할 수 있다.
서버에서, 사용자가 사이트에 접근하기 전에 로그인을 시키고자 한다면 HTTP 401 Unauthorized 응답코드를 브라우저에 보낼 수 있다.
WWW-Authenticate
헤더를 반환하여 로그인하라고 요청한다.Authorization
헤더에 토큰을 포함하여 전송하여, 사용자 식별을 시도한다.사용자를 식별하는 데 사용할 수 있지만, 문제가 있다.
참고자료
]]>none blocking
에 대한 이야기와🌕🌑🌑
setTimer에서부터 promise까지 동시성 모델을 기반으로 구현하며, 루프 제어권의 통제에 대하여 알아본다.
1 | const Item = class { |
performance.now()
Set
value
1 | time 현재시간 |
cf__2
requestAnimationFrame
- 브라우저에게 수행하기를 원하는 애니메이션을 알리고, 다음 리페인트가 진행되기 전에 해당 애니메이션을 업데이트하는 함수를 호출하게 한다.
- 리페인트 이전에 실행할 콜백을 인자로 받는다.
- 엔진이 렌더링이 끝나면 직접 발생시키는 함수
1 | const timeout = (block: Funtion, time:number) => |
1 | timeout(_ => console.log("hello"), 1000); |
방금 구현한 setTimer를 동시성 모델로 구현해보면?
좀더 큰 그림에서 보면?
1 | const working = _ => {}; |
requestAnimationFrame
으로 내부함수 f
가 실행requestAnimationFrame
으로 f
함수를 다시 실행시킨다.1 | const infinity: Iterator = (function*(){ |
1 | // lib.es2015.iterable.d.ts |
[Symbol.iterator]()
)를 호출하면 iterator 객체를 주는데,for...of
를 사용하지 못한다.yield
가 일어날 때마다 next
로 다음 턴을 줄 수 있다.function*
suspend
가 일어난 곳에서 resume
이 일어난다.suspend
resume
1 | const gene = function*(max:number, load:number, block:Function){ |
gene.next()
1 | const nbFor = (max, load, block) => { |
제어 시스템의 반제어권을 외부에 줌으로써
내부에서 제어와 관련된 로직을 분리시킬수 있게 된다는게
제너레이터의 장점
then
을 사용하는 것은1 | const gene2 = function*(max, load, block) { |
1 | const nbFor = (max, load, block) => { |
none blocking
에 대한 이야기와🌕🌑🌑
각각의 테스크가 같은 메모리를 바라볼 경우 문제가 생긴다.
즉, 동시성은 같이 쓰는 메모리를 어떻게 할지가 가장 어렵다.
Blocking
을 걸어서 다른 워커가 접근하지 못하도록한다. shared memory
와 atomic
이라는 개념으로 병행성 가능해짐.동시성에서 우리가 일을 시킬 수 있는 워커는 하나다.
자바스크립트 엔진을 동시성 모델로 표현해보자.
- 모든 비동기 API들은 작업이 완료되면 콜백 함수를 태스크 큐에 추가한다.
- 이벤트 루프는 ‘현재 실행중인 태스크가 없을 때’(주로 호출 스택이 비워졌을 때) 태스크 큐의 첫 번째 태스크를 꺼내와 실행한다.
setTimeout
, setInterval
window.postmessage
, localstrage
-sessionstorage
간의 메세지 등등멀티 스레드 문제도 synchronized문제가 생기기때문에
콜백 큐처럼 guard를 두어서 guard가 처리하게끔 설계함.
none blocking
에 대한 이야기와🌕🌑🌑
Loading
: 적재되는 중
instruction
- fetching & decoding
instruction
: CPU에서 해석할 수 있는 명령체계로 우리의 코드를 바꿔놓는 것메모리의 첫번째 명령을 실행한다.
execution
terminate
가 일어난다.sync flow
4번과 5번은 반복
자바스크립트의 런타임은 브라우저 로드에서부터 런타임으로 친다.
1 | a = 'TEST' |
중간에 쿠션을 두는 개념
1 | a = "TEST" |
.
: 쿠션을 친다.
이 원리를 사용하여 linked list, 디자인패턴, 객체지향의 추상클래스도 만든다.
goto
라는 명령어를 통해서 sync flow의 작동을 제어할 수 있다.cf__1 의존성 역전 / 제어 역전
- 의존성 역전: 추상적인 것에 의존하겠어.
- 제어 역전: 추상적인 행동을 할 것이라고 전제하여 제어문을 짜는 것.
Sync Flow가 납득할 만한 시간 내에 종료되는 것
다른 수단
으로 값을 반환하는 것Promise
callback function
iterations
sync 라는 순차적으로만 짤 수 있다는 식으로 처음부터 배웠기 때문에
우리는 async가 어색한 것이다.
Continuation
(컨텍스트라고 생각해되 된다.)none blocking
에 대한 이야기와🌕🌑🌑
오늘날의 자바스크립트 동향과 ECMAScript에 대해서 알아본다. ECMAScript가 버전업이 될때의 과정과, ES6 이후(~ES10)에 표준이 된 스펙들 중 일부를 알아본다. 또한 proposal에 올라온 목록과 체택되진 않았지만 이미 몇몇 브라우저에 적용된 개념들에 대해서 알아본다.
자바스크립트의 ECMAScript를 알아보기전에 우리는 프론트 개발자로써 어느 과정까지 건드리고 있는지를 알아보고, ECMAScript에 조금 더 집중할 수 있는 상황에 대해서 알아본다.
호환성이라던지, 브라우저에서 어떻게 실행할지는
트랜스파일러나 패키징이 알아서 책임지게 하고,
개발자가 코드에 집중할 수 있는 환경이 만들어졌다고도 할 수 있다.
ECMA스크립트는 차기버전을 정하는 순서가 그 해의 상반기에 정해진다.
내년 상반기에 확정될 ES11에 대한 draft작업이 되고 있음 (2019년 10월기준)
2019가 재정되자마자 공식문서 레포에는 다음버전의 레포가 떠진다.
현재 표준은 당연히 ES10이다
이번 강의에서는 ES11을 배울 것이다.
알고 있는 자바스크립트는 옛날 기준의 자바스크립트이다.
자바스크립트는 1년 기준으로 변한다.
지금 알고 있는 지식은 IE11때까지의 지식이구나 라고 알고 있어도 된다.
자바스크립트라는 언어를 따라가기 위해 표준에 대해 알아보고 이해한다.
C#이후에 업데이트가 가장 많이 일어나는 언어이다.
CSS
나 W3C
도 비슷한 사정최신판을 쓰기 위해서는 크롬을 사용해야하고,
크롬에서만 반영된 스펙을 안볼 수 없다.
ES5
이후에 중요한 부분
5
에서 함수를 상속받거나 배열을 상속받는 클래스를 만들 수 없다.1 | const [a, ...[b, ...c]] = [1,2,3,4] |
shared memory와 atomics를 알아보기 전에 알아야할 웹 워커 개념
웹 워커는 스크립트 실행을 메인 쓰레드가 아니라 백그라운드 쓰레드에서 실행할 수 있도록 해주는 기술
무거운 작업을 분리된 쓰레드에서 처리할 수 있다.
메인 쓰레드(일반적으로 UI 쓰레드)는 멈춤, 속도저하 없이 동작할 수 있게 된다.
Worker는 Worker() 생성자를 통해 생성된다.
JavaScript 파일에 포함된 코드를 워커스레드에서 실행한다.
Worker는 현재 Window와 분리된 DuplicatedWorkerGlobalScope 라는 별도의 Global context에서 동작한다.
몇가지 제한사항
웹 워커 종류
Dedicated Worker
Worker.postMessage()
메세지 전송Worker.onmessage
응답Shared worker 참고
Chrome Worker
Audio Workers
웹 어셈블리어에서 적극적으로 사용 중.
웹 워커는 멀티 스레드 패턴이 아닌 워커 스레드 패턴
웹워커가 만들어졌을 때는 스레드를 여러개 지원하지만
싱글 스레드라는 컨텍스트를 깨먹지 않도록 설계되었다.
문제점은 느리다.
당연하게도 동시성 문제가 생긴다.
Optional catch
1 | try { |
1 | try { |
아래 것은 크롬이 이미 구현
#
을 붙여서 사용한다.)#
을 붙여서 사용한다.)?.
??
자바스크립트는 현대 나온 언어 중에 가장 어렵다. 현대 모든 언어 중에 제일 장점이라고 불리는 것을 연마다 넣고 있다. 언어에서 어려운 개념을 다 넣고 있다.. 광범위한 언어적 지식을 요구하고 있다.
참고자료
]]>주식 그래프 봇 (매분 HTTP GET 요청을 보내 얻은 데이터로 그래프 생성)
웹 통계조사 로봇 (통계 정보를 수집)
검색엔진 로봇 (모든 문서를 수집)
가격 비교 로봇 (상품 가격 DB를 만들기 위해 온라인 쇼핑몰 웹페이지 수집)
그렇다면 크롤러들은 어떻게 동작할까?
순한은 크롤러에게 해롭다.
트리와 해시테이블 / 느슨한 존재 비트맵 / 체크포인트 / 파티셔닝
트리와 해시테이블
느슨한 존재 비트맵 Lossy presence bit maps
모르겠다.
url을 숫자형태의 비트로 만들어서 저장하고, 같은 존재비트가 있으면 이미 크롤링되었다고 간주하는 듯
체크포인트 checkpoint
파티셔닝 Partitioning
같은 문서를 가리키는 다른URL들
WIP..
참고자료
]]>처리단계는 7단계로 이루어져 있다.
네트워크 커넥션에서의 활동을 감지하고,
들어오는 데이터를 읽어들인다.
요청 메세지를 여러 부분으로 파싱하여
헤더 부분을 조작하기 쉬운 자료 구조에 담는다.
캐싱 소프트웨어가 헤더 필드를 처리하고 조작하기 쉽게 만들어 준다.
URL을 알아내고 그에 해당하는 로컬 사본이 있는지 검사한다.
메모리에 저장되어있을 수도 있고,
디스크나
근처 다른 컴퓨터에 있을 수 있다.
문서를 로컬에서 가져올 수 없다면, 상황이나 설정에 따라서
원서버나 부모프락시에서 가져오거나
혹은 실패를 반환한다.
캐시 된 객체는 서버 응답 본문과 원서버 응답 헤더를 포함하므로
캐시 적중 동안 올바른 서버 헤더가 반환될 수 있다.
객체가 얼마나 오랫동안 캐시에 머무르고 있었는지 알려주는 기록이나
얼마나 자주 사용되었는지 등에 대한
몇몇 메타데이터를 포함한다.
HTTP는 캐시가 일정 기간 동안 서버 문서의 사본을 보유할 수 있도록 해준다.
304 Not Modified
)신선도 검사 알고리즘은 아래에.
캐시 된 응답을 원서버에서 온 것처럼 보이게 하고 싶기 때문에
캐시는 캐시 된 서버 응답 헤더를 토대로 응답 헤더를 생성한다.
캐시는 클라에 맞게 이 헤더를 조정해야 하는 책임이 있다.
Cache-Control
, Age
, Expires
헤더)Via
헤더를 포함시킨다.대부분의 캐시는 로그 파일과 캐시 사용 통계를 유지한다.
많은 캐시 제품이 커스텀 로그 파일을 허용한다.
HTTP는 어떤 캐시가 사본을 갖고 있는지 서버가 기억하지 않더라도,
캐시 된 사본이 서버와 충분히 일치하도록 유지할 수 있게 해주는 매커니즘을 갖고 있다.
매커니즘은 문서 만료와 서버 재검사라고 부른다.
HTTP는 Cache-Control
과 Expires
라는 헤더들을 이용하여
원서버가 각 문서에 유효기간을 붙일 수 있게 해준다.
캐시 문서가 만료되기 전에,
캐시는 필요하다면 서버와의 접촉 없이 사본을 제공할 수 있다.
캐시 된 문서가 만료되면,
캐시는 반드시 서버와 문서에 변경된 것이 있는지 검사해야 하며, (변경이 없으면 304 Not Modified
)
만약 그렇다면 신선한 사본을 얻어와야 한다. (새 유효기간과 함께)
Expires
와 Cache-Control:max-age
헤더는 기본적으로 같은 일을 하지만,
절대 시간은 컴퓨터의 시계가 올바르게 맞추어져 있을 것을 요구한다.
절대 유효기간을 명시한다.
만약 유효기간이 경과했다면, 그 문서는 더 이상 신선하지 않다.
캐시 된 문서가 만료되었다는 것은,
그 문서가 원서버에 현재 존재하는 것과 실제로 다르다는 것을 의미하지는 않으며,
이제 검사할 시간이 되었음을 뜻한다.
캐시가 원서버에게 문서가 변경되었는지의 여부를 묻는 것
콘텐츠가 변경되었다면:
콘텐츠가 변경되지 않았다면:
캐시는 문서의 신선도를 매 요청마다 검증할 필요가 없다.
HTTP 프로토콜은 캐시가 다음 중 하나를 반환할 것을 요구한다.
HTTP의 조건부 메서드는 재검사를 효율적으로 만들어준다.
HTTP는 캐시가 서버에게 조건부 GET이라는 요청을 보낼 수 있도록 해준다.
If-Modified-Since
: 날짜 재검사1 | If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT |
줄여서 IMS 요청으로 불린다.
서버에게 리소스가 특정 날짜 이후로 변경된 경우에만 요청한 본문을 보내달라고 한다.
만약 문서가 주어진 날짜 이후에 변경되지 않았다면, 조건은(If-Modified-Since) 거짓이고
서버는 304 Not Modified
응답메세지를 클라에게 돌려준다.
효율을 위해 본문은 보내지 않는다.
응답 헤더들을 포함하지만, 원래 돌려줘야 할 것에서 갱신이 필요한 것만을 보내준다. (보통 새 만료 날짜만 보내준다.)
If-Modified-Since 헤더는 Last-Modified 헤더와 함께 동작한다.
원서버는 제공하는 문서에 최근 변경 일시를 붙인다.
마지막 배포 시간이 Last-Modified로 내려온다.
캐시가 캐시 된 문서를 재검사하려고 할때,
캐시 된 사본이 마지막으로 수정된 날짜가 담긴 If-Modified-Since헤더를 포함한다.
1 | If-Modified-Since: <캐시 된 마지막 수정일> |
몇몇 웹서버는 If-Modified-Since를 실제 날짜 비교로 구현하지 않는다.
대신 IMS 날짜와 최근 변경일 간의 문자열 비교를 수행한다.
GET 또는 HEAD에서만 사용 가능하다.
일반적인 사용예) ETag가 없는 캐시 된 엔티티로 업데이트한다.
If-None-Match와 함께 사용 시 무시된다.
If-None-Match
: 엔터티 태그 재검사서버는 무서에 대한 일련번호와 같이 동작하는 특별한 태그를 제공할 수 있다.(ETag)
캐시 된 태그가 서버에 있는 문서의 태그와 다를 때만 요청을 처리한다.
최근 변경일시 재검사가 행해지기 어려운 상황이 있다.
1 | 조건부 요청 |
1 | 응답 |
강한 검사기는 콘텐츠가 바뀔 때마다 바뀐다.
약한 검사기는 어느 정도 콘텐츠 변경을 허용하지만, 콘텐츠의 중요한 의미가 변경되면 함께 변경된다.
W/
접두사로 약한 검사기를 구분한다.1 | ETag: W/"v2.6" |
아래는 HTTP는 문서가 얼마나 오랫동안 캐시될 수 있게 할 것인지,
서버가 설정할 수 있는 여러 가지 방법이다.
Cache-control: no-cache
Cache-control: no-store
Cache-control: must-revalidate
Cache-Control: max-age=<seconds>
Cache-control: s-maxage=<seconds>
Expires
날짜 헤더를 응답에 첨부할 수 있다.캐시가 검증되지 않은 캐시 된 객체로 응답하는 것을 막는다.
Cache-control: no-store
: 캐시가 그 응답의 사본을 만드는 것을 금지한다.Cache-control: no-cache
: 로컬 캐시 저장소에 저장될 수 있다. 다만, 먼저 서버와 재검사를 하지 않고서는 캐시에서 클라로 제공될 수 없을 뿐이다.Do Not Serve From Cache Without Revalidation (재검사 없이 캐시에서 제공하지 마라)
Pragma: no-cache
: HTTP/1.0+ 하위 호환성을 위해 HTTP/1.1에 포함되어있다. 웬만하면 Cache-control: no-store
max-age
신선하다고 간주되었던 문서가 서버로부터 온 이후로 흐른 시간s-maxage
헤더는 공유된 캐시에만 적용된다.504 Gateway Timeout error
를 반환해야 한다.1 | $마지막_수정이후로_경과한_시간 = max(0, $서버의_Date - $서버의_Last_Modified) |
클라는 Cache-control 요청 헤더를 사용하여 만료 제약을 엄격하게 하거나, 느슨하게 할 수 있다.
Cache-Control: max-stale[=<seconds>]
: 클라이언트가 캐시의 만료 시간을 초과한 응답을 받아들일지를 나타낸다. 초가 지정되면, 클라는 만료시간이 그 매개변수 값만큼 지난 문서도 받아들인다.Cache-Control: min-fresh=<seconds>
: 클라는 지금으로부터 s초 후까지 신선한 문서만을 받아들인다.Cache-Control: max-age=<seconds>
: s초보다 오랫동안 캐시 된 문서를 반환할 수 없다.Cache-control: no-cache
: 캐시 된 리소스는 재검사하기 전에는 받아들이지 않을 것이다.Cache-control: no-store
: 저장소에서 문서의 흔적을 빨리 삭제해야 한다. 문서에는 민감한 정보가 포함되어 있기 때문Cache-control: only-if-cached
: 클라는 캐시에 들어있는 사본만을 원한다.캐시 된 사본의 나이가 신선도 수명보다 작으면 사본은 제공해주기에 충분히 신선한 것이다.
1 | $충분히_신선한가 = $나이 < $신선도_수명 |
문서의 나이: 서버가 문서를 보낸 후(혹은 서버가 마지막으로 재검사한 후) 그 문서가 나이를 먹은 시간의 총합이다.
캐시는 문서 응답이 어떻게 왔는지 모르기 때문에, 문서가 완전히 새롭다고 가정하지 못한다.
Age
헤더를 통해 명시적으로든
서버가 생성한 Date 헤더를 통해 계산하든 간에
문서의 나이를 판별해야 한다.
1 | $겉보기_나이 = max(0, $응답을_받은_시각 - $Date_헤더값) |
모든 컴퓨터가 똑같이 정확한 시계를 갖고 있다면,
캐시 된 문서의 나이는 단순히
현재 시간에서 서버가 문서를 보낸 시간(Date 헤더)을 뺀 겉보기 나이가 될 것이다.
1 | $겉보기_나이 = $응답을_받은_시각 - $Date_헤더값 |
모든 컴퓨터는 똑같이 정확한 시계를 갖고 있지 않다.
클록 스큐 clock skew: 두 컴퓨터의 시계 설정 차이로 인한 문제
클록 스큐 때문에 겉보기 나이는 종종 부정확하며 때로는 음수가 되기도 한다.
겉보기 나이가 음수가 될 경우 0으로 만들어야 한다.
1 | $겉보기_나이 = max(0, $응답을_받은_시각 - $Date_헤더값) |
Age 헤더 값은 문서가 프락시들을 통과하면서 점점 늘어난다.
상대 나이값은 가장 큰 것(보수적)이 선택된다.
1 | $겉보기_나이 = max(0, $응답을_받은_시각 - $Date_헤더값) |
1 | $겉보기_나이 = max(0, $응답을_받은_시각 - $Date_헤더값) |
1 | $나이 = $문서가_우리의_캐시에_도착했을_때의_나이 + $사본이_우리의_캐시에_머무른_시간; |
1 | sub 서버_신선도_한계 { |
전체 과정은 문서의 나이와 신선도 한계라는 두 가지 변수가 관련되어 있다.
참고자료
]]>음?
보스턴과 샌프란시스코 사이의 거리는 약 4,400km이다. 어떤 웹페이자가 20개의 작은 이미지를 포함하고 있는데, 모두가 샌프란시스코에 있는 한 서버에 들어있다고 가정해보자.
보스턴에 있는 클라가 서버로 동시에 4개의 커넥션을 열고, 그 커넥션을 유지한다면, 다운 받을 때의 빛의 속도로 인한 지연은 거의 1/4초가 된다.(240밀리초) 만약 서버가 보스턴에서 더 멀리 10,800km 떨어진 도쿄라면 600밀리초로 커진다.
cache hit
cache miss
원서버 콘텐츠는 변경될 수 있기 때문에,
캐시는 반드시 그들이 갖고 있는 사본이 여전히 최신인지 서버를 통해 점검해야한다.!!
이러한 신선도 검사를 HTTP 재검사라 부른다.
HTTP는 서버로부터 전체 객체를 가져오지 않고도, 콘텐츠가 여전히 신선한지 빠르게 검사할 수 있는 특별한 요청을 정의했다.
대부분의 캐시는 클라가 사본을 요청하였으며,
그 사본이 검사를 할 필요가 있을 정도로 충분히 오래된 경우에만 재검사를 한다.
콘텐츠가 변경되지 않았다면, 서버는 아주 작은 304 Not Modified
응답을 보낸다.
If-Modified-Since
헤더If-Modified-Since
요청이 서버에 도착했을 때 일어날 수 있는 3가지 상황
문서적중률과 바이트 단위 적중률은 둘다 캐시 성능에 대한 유용한 지표다.
캐시가 요청을 처리하는 비율을 캐시 적중률 혹은 문서 적중률이라고 부르기도 한다.
실제 적중률은
클라가 응답이 캐시에서 왔는지 알아내는 한가지 방법은 Date 헤더를 이용하는 것이다.
토폴로지(영어: topology, 문화어: 망구성방식)는 컴퓨터 네트워크의 요소들(링크, 노드 등)을 물리적으로 연결해 놓은 것, 또는 그 연결 방식을 말한다. 로컬 영역 네트워크(LAN)은 물리적 토폴로지와 논리적 토폴로지 둘 다 보여 줄 수 있는 네트워크의 한 예이다. 출처
- 토폴로지 종류
- 버스 토폴로지
- 스타 토폴로지
- 링 토폴로지
- 트리 토폴로지
공용 캐시는 캐시 프락시 서버 혹은 더 흔한 프락시 캐시라고 불리는 특별한 종류의 공유된 프락시 서버다.
프락시 캐시는 로컬 캐시에서 문서를 제공하거나, 혹은 사용자 입장에서 서버에 접근한다.
공용캐시에는 여러 사용자가 접근하기 때문에, 불필요한 트래픽을 줄일 수 있는 더 많은 기회가 있다.
각 개인 전용 캐시는 같은 문서를 네트워크를 거쳐 여러번 가져온다.
공용 캐시에서, 캐시는 자주 찾는 객체를 단 한번만 가져와
모든 요청에 대해 공유된 사본을 제공함으로써 네트워크 트래픽을 줄인다.
수동 프락시를 지정하거나, 프락시 자동설정 파일을 설정함으로써, 브라우저가 프락시 캐시를 사용하도록 설정할 수 있다.
잘 모르겠다.
캐시망의 프락시 캐시는
어떤 부모 캐시와 대화할 것인지,
아니면 요청이 캐시를 완전히 우회해서 원 서버로 바로 가도록 할 것인지에 대한
캐시 커뮤니케이션 결정을 동적으로 내린다.
캐시망 안에서의 콘텐츠 라우팅을 위해 설계된 캐시들은
다음에 나열된 일들을 모두 할 수 있을 것이다.
참고자료
]]>딥링크는 단순한 개념이다.
특정 콘텐츠에 직접 도달하는 모든 링크를 뜻하는데, 형태는 스킴(scheme)과 호스트(host)로 구성된 URL(Uniform Resource Locator)이며, 웹환경에서도 쉽게 적용할 수 있다.
url의 자세한 설명은 여기
현재 url 또한 url하나로 블로그 글에 직접 도달할 수 있기 때문에 딥링크라고 말할 수 있다. (https://feel5ny.github.io/2019/09/22/Communication_001/
) 앱에서도 특정 콘텐츠를 직접 도달할 수 있도록, 여러가지 딥링크 형태들을 활용한다. (url 스킴, 유니버설 링크..)
굿닥은 원링크 사용
제플린의 공유 url
앱의 특정 콘텐츠를 공유하고 싶을 경우에도 딥링크를 사용할 수 있다.
딥링크를 사용할 경우,
goodoc://
단점
앱이 설치되어있을 경우
이미지 출처: branch
앱이 미설치 일 경우 대체 url로 이동된다.
이미지 출처: branch
웹서버에서 Universal link(ios) 처리하는 흐름
단점
이를 해결하기 위해 디퍼드 딥링크를 사용한다.
이런 장점을 지닌 디퍼드 딥링크는 각각의 OS 별로 구현하는 방식이 다르다.
참고
모바일 앱 마케팅을 하는 곳이라면 어트리뷰션 툴 사용은 필수이다. 앱 설치 또는 구매와 같은 인앱이벤트에 대한 원인이 되는 광고 클릭을 찾는 것이 바로 어트리뷰션 툴의 목적이라고 할 수 있다.
어트리뷰션(Attribution): 어떤 행동에 대한 원인을 찾는 과정
참고자료
]]>ISP: Internet Service Provider (KT, SKT, LG+)
서버 가속기라고 불린다.
사용자가 필터링 서비스에 가입했다면, HTTP 요청이 필터링 프락시를 통과하도록 할 수 있다.
트랜스 코딩: 데이터의 표현방식을 변환하는 것
동적 부모 선택의 몇 가지 사례
클라 트래픽이 프록시로 가도록 만드는 방법 4가지
인터셉트 프록시 (= transparent proxy): HTTP 트래픽을 지켜보고 가로채어 클라 모르게 트래픽을 프록시로 보내는 스위칭 장치와, 라우팅 장치가 필요.
자바스크립트 PAC 파일의 URI를 브라우저에 설정해야 한다.
.pac
application/x-ns-proxy-autoconfig
FindProxyForURL(url, host)
함수를 정의해야 한다.1 | FindProxyForURL(url, host): "DIRECT" | `PROXY ${host}:${port}` | `SOCKS ${host}:${port}` |
1 | function FindProxyForURL(url, host) { |
웹 프록시 자동 발견 프로토콜 Web Proxy Auto-Discovery Protocol
웹 서버와 웹 프록시 메세지의 문법은 간다.
요청 URI가 달라진다.
1 | 클라 => 서버 |
애초에 단일 서버 기준으로 메세지 설계가 되었었다.
프록시가 부상하면서 부분 URI는 문제가 되었고, 프록시 기반 게이트웨이는 URI 스킴을 알 필요가 있었기 때문에 부분URI가 아닌 전체 URI를 보낸다.
프록시 서버는 요청 URI의 변경에 엄격해서는 안된다.
사이드 이펙트를 일으킬 수 있다.
Via
헤더Via
는 메세지가 지나는 각 중간 노드(Proxy or GateWay)의 정보를 나열한다.1 | Via: 1.1 proxy-62.irenes-isp.net, 1.0 cache.joes-hardware.com |
waypoint
목록1 | Via: ([ protocol-name "/ ] protocol-version ( host [ ":" port] ) [ comment ]), (...) |
1 | Via: 1.1 62e18ccb7bd6.cloudfront.net (CloudFront) |
Via
헤더는 거의 요청 Via 헤더와 반대다.1 | Server: nginx/1.10.3 (Ubuntu) |
1 | Via 1.0 foo, 1.1 devirus.company.com, 1.1 access-logger.company.com |
TRACE
메서드407 Proxy Authorization Required
상태코드를 Proxy-Authenticate
헤더 필드와 함께 반환할 수 있다.407
응답을 받게되면, 사용자에게 요구되는 자격을 수집한다.Proxy-Authenticate
헤더 필드에 자격을 담아서 다시 보낸다.407
응답을 보낸다.OPTIONS
메서드는 서버나 웹 서버의 특정 리소스가요청 URI에 의해 식별되는 자원에 대해 지원되는 메서드들이나 서버가 지원하는 모든 메서드를 열거한다.
1 | Allow: GET, HEAD, PUT |
서버는 클라가 원하는 모든 메서드를 지원해야할 의무는 없다.
요청에 대한 응답에는 실제로 지원하는 메서드들을 열거하는 Allow 헤더를 포함시켜야한다.
프락시는 Allow 필드를 수정할 수 없다.
참고자료
]]>그밖에도 숫자에 볼륨감이 없어서 한글의 깔끔함에 비해서 영문과 숫자에 아쉬움들이 있곤했다. 글자간 커링도 작고, 카운터(속공간)도 작은 듯하고..
그래도 점점 노토산스를 자주 애용하고 보다보니, 그냥 저냥 적응하고 있었는데, 회사 프로젝트에서 요 노토산스에 대해서 디자인 요청이 왔다.
한글은 노토산스로, 영문과 숫자, 특수문자는 오픈산스로 적용해주세요! (여기서 특수문자는 키보드서 shift와 함께 사용가능한 특수문자들)
듣던 중에 반가운 소리였다.(😘) 노토산스에 대해 개인적인 취향?을 해소해주는 디자인 요청이었기 때문에.
그나저나 이걸 어떻게 적용할지는 고민이었다. 일일이 적용하는건 절대 말이 안된다고 생각했고, 다른 방법이 있을거라고 생각해보며 이리저리 서칭을 해보았다.
이 포스팅에서는 어떤 원리로 font가 분리되어서 적용되는지에 대해서 설명하려고 한다.
@font-face
에 대해서 알아보며, 크게는 @font-face
를 포함하고 있는 at-rule의 개념과 css문의 개념을 가볍게 살펴본다. 바로 방법을 알고싶은 분들은 해당 단락은 넘어가도된다.@font-face
에서 제공해주는 unicode range
에 대해서 살펴본다.@font-face
에서 적용하는 방법을 알아본다.@font-face
우리가 보통 사용하는 규칙집합(선택자-선언 블록 쌍)은 큰 규칙집합 목록만으로 구성된 스타일 시트의 주요 구성 블록이다.
1 | p { |
statement(문)은 비공백 문자로 시작하여 첫 번째 닫는 중괄호 또는 세미콜론 (문자열 외에, 이스케이프되지 않고 다른 {}
, ()
및 []
쌍에 포함되지 않는) 으로 끝나는 구성 블록이다.
다음과 같은 다른 종류의 문이 있다
@
(U+0040 COMMERCIAL AT
)로 시작한 다음
statement의 마지막, 즉 블록 다음에는 세미콜론(;
)이 오며,
또는 다음 블록의 끝까지 계속 식별자가 뒤따른다.
식별자에 의해 정의된 각 유형의 at-rule은, 자체 내부 구문 및 의미(semantics)가 있을 수 있다.
@charset
또는 @import
같은), @media
또는 @document
같은) @font-face
같은)를 전달하는 데 사용된다.중첩 문(nested statements)
@media
는 브라우저가 돌아가는 장치가 표현된 조건과 일치하는 경우에만 적용된다.@document
는 현재 페이지가 일부 조건과 일치하는 경우에만 적용된다. (아직 실험)1 | @document url("https://www.example.com/") { |
@font-face
@font-face
CSS는 텍스트를 표시할 사용자 정의 글꼴을 지정한다.url()
함수를 사용하여 지정한 글꼴 리소스를 다운로드하여 사용한다.@font-face
는 폰트 제작자들이 자신의 글꼴을 제공할 수 있게 함으로써 “웹 세이프” 글꼴 (즉, 보편적화된 흔한 웹 글꼴)에 국한되지 않고 콘텐츠를 디자인할 수 있게 한다. url()
과 local()
을 함께 사용하는 것이 일반적이어서,@font-face
의 속성중 unicode-range
사용하기우리는 css에 정의된 글꼴정보가 글자에 적용될 시점에, 특정 문자는 필터하면서 적용되길 바라고 있다.
unicode-range
속성@font-face
의 속성 중에는 unicode-range
라는 속성이 존재한다.
해당 속성은 글꼴에서 사용될 유니 코드 코드 포인트의 범위를 지정할 수 있다. 우리는 unicode-range
를 사용하여 숫자와 영문, 특수문자의 범위를 알아내고, 해당 범위에 폰트를 지정할 것이다.
unicode
와 범위1 | 1. 특수문자 범위: U+0020-002F, U+003A-0040, U+005B-0060, U+007B-007E |
font-family
에 사용할 때에는 다르게 적용하고 싶은 문자마다 css를 적용하는 것이 아니다.font-family
에 따로 Open-sans 명시 없이 그대로 Noto-sans가 명시된 상태에서 내부적으로 적용시점에만 따로 적용되게 하면 된다.font-family
를 갖는 두개의 @font-face
가 필요하다. @font-face
에는 unicode-range
없이 전체 적용할 noto-sans를 연결하고@font-face
에는 unicode-range
를 정의하고 해당 범위에만 적용할 open-sans를 연결한다.1 |
|
참고자료
]]>운영체제는
웹 서버는
node.js로 간단 웹서버를 구현해 보았다.
공통적으로는 아래 그림에서 하는 일을 한다.
아래는 어떻게 ident 프로토콜이 동작하는지 보여준다.
공공 인터넷에서는 다음과 같은 이유로 잘 동작하지 않는다.
요청 메세지를 파싱할 때, 웹서버는 다음과 같은 일을 한다.
CRLF
) 문자열로 끝난다. (참고)CRLF
로 끝난다.CRLF
로 끝나는 빈 줄을 찾아낸다.Content-Length
헤더로 정의한다.)웹 서버는 아키텍처의 차이에 따라 요청을 처리하는 방식도 달라진다.
프로세스란 어떤 프로그램의 자신만의 변수 집합을 갖는 하나의 독립된 제어 흐름이다.
스레드는 프로세스의 더 빠르고 더 효율적인 버전이다.
스레드와 프로세스 모두 하나의 프로그램이 여러 작업을 동시에 할 수 있게 해준다.
-
docroot
로 불린다.httpd.conf 설정 파일에 docroot 경로를 설정해두면 요청 헤더의 URI를 문서 루트 뒤에 붙인다.
1 | GET /specials/joy.gif HTTP/1.0 |
1 | DocumentRoot /usr/local/httpd/files |
/usr/local/httpd/files
+ /specials/joy.gif
1 | https://feel5ny.github.io/.../ |
/
과 물결표~
다음에 사용자 이름이 오는 것으로 시작하는 URI는 그 사용자의 개인 문서 루트를 가리킨다.docroot
는 주로 사용자 홈 디렉터리 안에 있는 public_html로 불리는 디렉터리지만, 설정에 따라 다르다.index.html
혹은 index.htm
으로 이름 붙은 파일을 찾아 반환한다.본문이 있다면, 응답 메세지는 주로 다음을 포함한다.
웹 서버에게는 응답 본문의 MIME타입을 결정해야하는 책임이 있다.
MIME타입과 리소스를 연결하는 여러 가지 방법이다.
매직 넘버. 다른 종류의 파일의 문법은 구조 상 보여지는 타입을 결정하는 데 도움을 줍니다. 예를 들어, 각 GIF 파일들은 47 49 46 38 16진수 값 [GIF89]로 시작되며 PNG 파일의 경우 89 50 4E 47 [.PNG]로 시작됩니다. 파일의 모든 타입들이 이런 매직 넘버를 가지고 있는 것은 아니므로 100% 신뢰할 만한 시스템은 아니기도 합니다.
출처
301
303
, 307
303
, 307
303
, 307
303
, 307
301 Moved Permanetly
상태코드는 이런 종류의 리다이렉트를 위해 사용된다.303 See Other
과 307 Temporary Redirect
상태코드는 이런 종류의 리다이렉트를 위해 사용된다.상태 정보가 추가된 URL은 흔히 뚱뚱한 URL이라고도 부른다.
303 See Other
과 307 Temporary Redirect
상태코드를 사용한다.303 See Other
과 307 Temporary Redirect
상태코드를 사용한다.303 See Other
과 307 Temporary Redirect
상태코드를 사용한다./
)을 빠뜨렸다면,Content-Length
헤더를 바르게 계산하기 위해 특별히 주의를 필요로 하는 경우,참고자료
]]>웹 클라는 보통 같은 사이트에 여러 개의 커넥션을 맺는다. 즉 같은 서버에 계속 요청
처리가 완료된 후에도 계속 연결된 상태로 있는 TCP 커넥션을 지속 커넥션이라고 부른다.
병렬 커넥션의 단점
지속 커넥션의 장점
지속 커넥션의 단점
지속 커넥션 + 병렬 커넥션은 가장 효과적
HTTP/1.1에서는 keep-alive는 사용하지 않기로 결정
아직 keep-alive 핸드셰이크가 널리 사용되고 있음.
HTTP/1.0 keep-alive 커넥션을 구현한 클라는 커넥션을 유지하기 위해서 요청에Connection: Keep-Alive
헤더를 포함시킨다.
이 요청을 받은 서버는 그다음 요청도 이 커넥션을 통해 받고자 한다면, 응답 메세지에 같은 헤더를 포함시켜 응답한다.
응답에 Connection: Keep-Alive
가 없으면, 클라는 서버가 keep-alive를 지원하지 않으며,
응답 메세지가 전송되고 나면 서버 커넥션을 끊을 것이라고 추정한다.
Connection: Keep-Alive
가 있을 때만 사용 가능하다.keep-alive의 동작은 Keep-Alive
헤더의 옵션들로 제어 가능하다
1 | Keep-Alive: timeout=5, max=1000 |
Connection: Keep-Alive
Connection: Keep-Alive
가 있을 때만 사용 가능하다.Connection: Keep-Alive
가 없을 경우 서버는 요청을 처리한 후 커넥션을 끊을 것이다.Connection: Keep-Alive
가 없을 경우 서버가 응답 후에 커넥션을 끊을 것임을 알 수 있다.Content-Length과 커넥션
Connection 헤더
Connection 헤더의 무조건 전달
Connection: Keep-Alive
헤더와 함께 메세지를 보내고, 커넥션을 유지하기를 요청한다.Connection
헤더를 이해하지 못해서 다음 서버에 메세지를 그대로 전달한다.Connection
헤더는 홉별 헤더다.(hop-by-hop): 오직 한 개의 전송 링크에만 적용되며, 다음 서버로 전달되어서는 안 된다.Connection: Keep-Alive
를 받은 웹 서버는 커넥션을 유지하자고 요청하는 것으로 잘못 판단하게 된다.Connection: Keep-Alive
헤더를 포함하여 응답한다.Connection
를 모른다.Connection: Keep-Alive
헤더를 포함하고 있는 응답메세지를 클라에게 전달한다.Connection
를 모르는 프락시는 모든 데이터를 클라에게 전달하고 서버가 커넥션을 끊기를 기다린다.프락시와 홉별 헤더
위의 잘못된 통신을 피하려면
RFC 7230
Proxy-Connection vs Connection header
Connection:close
헤더를 명시해야 한다.Connection:close
헤더가 없으면 응답 후에도 커넥션을 계속 유지하는 것으로 추정한다.Connection:close
를 보내지 않는 것이 서버가 커넥션을 영원히 유지하겠다는 것은 아니다.Connection:close
헤더를 포함해 보내면,Connection:close
헤더를 보내야 한다..close()
를 호출하면 TCP 커넥션의 입력 채널과 출력 채널의 커넥션을 모두 끊는다.shutdonw()
을 호출하면 입력 채널이나 출력 채널 중에 하나만을 개별적으로 끊는다.잘 모르겠다.
참고자료
]]>웹 브라우저가 TCP 커넥션을 통해서 웹 서버에 요청을 보낸다.
1 | https://feel5ny.github.io/index.html |
feel5ny.github.io
라는 호스트 명을 추출한다.185.199.111.153
의 80포트로 TCP 커넥션을 생성한다.IP 패킷이 포함하는 것.
패킷 구조는 아래와 같다.
그림출처
IP 헤더와 TCP 헤더는 아래와 같다.
그림출처
4가지 값으로 유일한 커넥션을 생성한다.
4가지 커넥션 구성요소를 똑같이 가리키고 있는 커넥션은 있을 수 없다.
다음과 같은 요인과 그로 인한 성능상의 문제를 포함해 영향을 주는 일반적인 TCP 관련 지연들에 대해서 다른다.
어떤 데이터를 전송하든, 새로운 TCP 커넥션을 열 때면,
TCP 소프트웨어는 커넥션을 맺기 위한 조건을 맞추기 위해 연속으로 IP 패킷을 교환한다.
다음은 TCP 커넥션이 핸드셰이크를 하는 순서다. (예전에 정리한 글)
SYN
(synchronize sequence numbers)라는 특별한 flag를 가진다.SYN
+ ACK
(acknowledgment) flag를 포함한 TCP 패킷을 클라에게 보낸다.ACK
)ACK
)데이터 보낼 때 같이 보내면 되겠다!
막상 HTTP에서는
TCP 느린 시작
튜닝
되어서,혼잡 윈도를 연다. opening the congestion window
TCP_NODELAY
TCP_NODELAY
파라미터 값을 설정하여 네이글 알고리즘을 비활성화하기도 한다.TIME_WAIT
의 누적과 포트 고갈2MSL
이라고 불리며 보통 2분 정도오래전, 라우터가 매우 느렸던 때에는 중복되는 패킷의 복제본이 삭제되기 전까지 인터넷에 있는 큐에 1분이 넘게 보관되어 있었기 때문에 최대 생명주기를 1분으로 정했다.
Time wait에 대한 글
카카오 블로그
toast 블로그
커넥션을 생성하고 최적화하는 HTTP 기술을 설명할 것이다.
HTTP header field name
임시적인 토큰값
: 커넥션에 대한 비표준 옵션을 의미close
: 커넥션이 작업이 완료되면 종료되어야 함을 의미.keep-alive
HTTP 커넥션의 성능을 향상시킬 수 있는 여러 최신 기술이 있다.
참고자료
]]>헤더에는
👆 특정 종류의 메세지에만 사용할 수 있는 헤더와,
🤚 더 일반 목적으로 사용할 수 있는 헤더,
👐 그리고 응답과 요청 메세지 양쪽 모두에서 정보를 제공하는 헤더가 있다.
1 | Connection: keep-alive |
Connection
: 클라와 서버가 요청/응답 연결에 대한 옵션을 정할 수 있게 해준다.Date
: 메세지가 언제 만들어졌는지에 대한 날짜와 시간을 제공한다.MIME-Version
: 발송자가 사용한 MIME의 버전을 알려준다.Trailer chunked transfer
: 인코딩된 메세지의 끝 부분에 위치한 헤더들의 목록을 나열한다.Transfer-Encoding
: 수신자에게 안전한 전송을 위해 메세지에 어떤 인코딩이 적용되었는지 말해준다.Upgrade
: 발송자가 업그레이드하길 원하는 새 버전이나 프로토콜을 알려준다.Via
: 이 메세지가 어떤 중개자를 거쳐 왔는지 보여준다.1 | Cache-Control: public, max-age=31536000 |
최신 버전의 HTTP는 매우 풍부한 캐시 매개변수의 집합을 가지고 있다.
Cache-Control
: 메세지와 함께 캐시 지시자를 전달하기 위해 사용한다.Pragma
: 메세지와 함께 지시자를 전달하는 또 다른 방법. 캐시에 국한되지 않는다. (HTTP/1.0)요청 메세지에서만 의미를 갖는 헤더다.
1 | From: webmaster@example.org |
Client-IP
: 클라가 실행된 컴퓨터의 IP를 제공한다.From
: 클라 사용자의 메일주소를 제공한다.Host
: 요청의 대상이 되는 서버의 호스트 명과 포트를 준다.Referer
: 현재의 요청 URI가 들어있었던 문서의 URL을 제공한다.User-Agent
: 요청을 보낸 어플리케이션의 이름을 서버에게 말해준다.UA-Color
: 클라 기기 디스플레이의 색상 능력에 대한 정보를 제공한다.UA-CPU
: 클라 CPU의 종류와 제조사를 알려준다.UA-Disp
: 클라 디스플레이 능력에 대한 정보를 제공한다.UA-OS
: 클라 기기에서 동작 중인 운영체제의 이름과 버전을 알려준다.UA-Pixels
: 클라 기기 디스플레이에 대한 픽셀 정보를 제공한다.1 | Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8 |
클라는 Accept 헤더들을 이용해 서버에게 자신의 선호와 능력을 알려줄 수 있다.
서버는 클라가 사용할 수도 없는 것을 전송하는데 시간과 대역폭을 낭비하지 않을 수 있다.
Accept
: 서버에게 서버가 보내도 되는 콘텐츠 타입을 MIME 타입를 말해준다.Accept-Charset
: 서버에게 서버가 보내도 되는 문자집합을 말해준다.Accept-Encoding
: 서버에게 서버가 보내도 되는 인코딩을 말해준다.Accept-Language
: 서버에게 서버가 보내도 되는 언어를 말해준다.TE
: 서버에게 서버가 보내도 되는 확장전송 코딩을 말해준다. (Transfer-Encoding)1 | Expect: 100-continue |
클라는 요청에 몇몇 제약을 넣기도 한다.
클라는 서버에게 요청에 응답하기 전에 먼저 조건이 참인지 확인하게 하는 제약을 포함시킬 수 있다.
Expect
: 클라가 요청에 필요한 서버의 행동을 열거할 수 있게 해준다.If-Match
: 문서의 엔터티 태그가 주어진 엔터티 태그와 일치하는 경우에만 문서를 가져온다.If-Modified-Since
: 주어진 날짜 이후에 리소스가 변경되지 않는다면 요청을 제한한다.If-None-Match
: 문서의 엔터티 태그가 주어진 엔터티 태그와 일치하지 않는 경우에만 문서를 가져온다.If-Range
: 문서의 특정 범위에 대한 요청을 할 수 있게 해준다.If-Unmodified-Since
: 주어진 날짜 이후에 리소스가 변경되었다면 요청을 제한한다.Range
: 서버가 범위 요청을 지원한다면, 리소스에 대한 특정 범위를 요청한다.bytes=200-1000
1 | Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l |
HTTP는 자체적으로 요청을 위한 간단한 인증요구/응답 체계를 갖고 있다.
요청하는 클라가 어느 정도의 리소스에 접근하기 전에 자신을 인증하게 함으로써, 트랜잭션을 약간 더 안전하게 만들고자 한다.
Authorization
: 클라가 서버에게 제공하는 인증 그 자체에 대한 정보를 담고 있다.Cookie
: 클라가 서버에게 토큰을 전달할 때 사용한다. 진짜 보안헤더는 아니지만, 보안에 영향을 줄 수 있다는 것은 확실하다.Cookie2
: 요청자가 지원하는 쿠키의 버전을 알려줄 때 사용한다.1 | Proxy-Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l |
Max-Forwards
: 요청이 원서버로 향하는 과정에서 다른 프락시나 게이트웨이로 전달될 수 있는 최대 횟수.Proxy-Authorization
: Authorization과 같으나 프락시에서 인증을 할 때 쓰인다.Proxy-Connection
: Connection과 같으나 프락시에서 연결을 맺을 때 쓰인다.응답 메세지는 그들만의 응답 헤더를 갖는다.
응답 헤더는 클라에게 부가 정보를 제공한다.
1 | Age: 24 |
Age
: 응답이 얼마나 오래되었는지Public
: 서버가 특정 리소스에 대해 지원하는 요청 메서드의 목록Retry-After
: 현재 리소스가 사용 불가능한 상태일 때, 언제 가능해지는지 날짜 혹은 시간Server
: 서버 어플리케이션의 이름과 버전Title
: HTML 문서에서 주어진 것과 같은 제목Warning
: 사유 구절에 있는 것보다 더 자세한 경고 메세지1 | Accept-Ranges: bytes |
서버에 프랑스어나 독일어로 번역된 HTML 문서가 있는 경우와 같이 여러 가지 표현이 가능한 상황이라면,
HTTP/1.1은 서버와 클라가 어떤 표현을 택할 것인가에 대한 협상을 할 수 있도록 지원한다.
Accept-Ranges
: 서버에게 서버가 보내도 되는 언어를 말해준다.Vary
: 서버가 확인해 보아야 하고, 그렇기 때문에 응답에 영향을 줄 수 있는 헤더들의 목록1 | Proxy-Authenticate: Basic realm="Access to the internal site" |
기본적인 인증 요구 헤더들이다.
Proxy-Authenticate
: 프락시에서 클라로 보낸 인증요구의 목록Set-Cookie
: 진짜 보안 헤더는 아니지만, 보안에 영향은 줄 수 있다. 서버가 클라를 인증할 수 있도록 클라 측에 토큰을 설정하기 위해 사용한다.Set-Cookie2
: Set-Cookie와 비슷하게 RFC 2965로 정의된 쿠키.WWW-Authenticate
: 서버에서 클라로 보낸 인증요구의 목록엔터티에 대해 설명하는 헤더들은 많다.
요청과 응답 양쪽 모두 엔터티를 포함할 수 있기 때문에,
이 헤더들은 양 타입의 메세지에 모두 나타날 수 있다.
1 | Allow: GET, POST, HEAD |
Allow
: 이 엔터티에 대해 수행될 수 있는 요청 메서드들을 나열한다.Location
: 클라에게 엔터티가 실제로 어디에 위치하고 있는지 말해준다. 수신자에게 리소스에 대한 (아마도 새로운) 위치 URL을 알려줄 때 사용한다.Location과 Content-Location는 다릅니다:
Location가 리다이렉션의 대상(혹은 새롭게 만들어진 문서의 URL)을 가르키는데 반해,
Content-Location은 더 이상의 컨텐츠 협상없이, 리소스 접근에 필요한 직접적인 URL을 가르킵니다.
Location은 응답과 연관된 헤더인데 반해, Content-Location 은 반환된 개체와 연관이 있습니다.
출처 mdn
1 | Content-Encoding: gzip |
엔터티의 콘텐츠에 대한 구체적인 정보를 제공한다.
콘텐츠의 종류, 크기, 기타 콘텐츠를 처리할 때 유용하게 활용될 수 있는 것들이다.
웹브라우저는 내용 유형을 기술한 Content-Type 헤더를 보고 그 객체를 어떻게 보여줄지 결정할 수 있다.
Content-Base
: 본문에서 사용된 상대 URL을 계산하기 위한 기저 URLContent-Encoding
: 본문에 적용된 어떤 인코딩Content-Language
: 본문을 이해하는데 가장 적절한 자연어Content-Length
: 본문의 길이나 크기Content-Location
: 리소스가 실제로 어디에 위치하는지Content-MD5
: 본문의 MD5 체크섬Content-Range
: 전체 리소스에서 이 엔터티가 해당하는 범위를 바이트 단위로 표현Content-Type
: 이 본문이 어떤 종류의 객체인지Content-Disposition
: 콘텐츠가 브라우저에 인라인으로 표시될 것으로 예상되는지, 즉 웹 페이지 또는 웹 페이지의 일부로서 또는 첨부 파일로 로컬로 다운로드 및 저장될 것으로 예상되는지를 나타내는 헤더다.1 | ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4" |
일반 캐싱 헤더는 언제 어떻게 캐시가 되어야 하는지에 대한 지시자를 제공한다.
엔터티 캐싱 헤더는 엔터티 캐싱에 대한 정보를 제공한다.
ETag
: 이 엔터티에 대한 엔터티 태그Expires
: 이 엔터티가 더 이상 유효하지 않아 원본을 다시 받아와야 하는 일시Last-Modified
: 가장 최근 이 엔터티가 변경된 일시참고자료
]]>1 | Expect: 100-continue |
서버가 100 Continue 값이 담긴 expect 헤더가 포함된 요청을 받는다면
받은 엔터티에 대한 최종 응답코드는 보내줘야 한다.
아래는 upgrade 헤더의 웹소켓으로 서버가 프로토콜을 바꿨다는 의미이다.
1 | HTTP/1.1 101 Switching Protocols |
GET
: 리소스를 가져왔고 메시지 바디에 전송되었다.HEAD
: 개체 헤더가 메시지 바디에 있다.POST
: 리소스가 명시하는 행동의 결과가 메시지 바디에 전송되었다.TRACE
: 서버가 요청받은 메시지가 메시지 바디에 포함되어있다.PUT
또는 DELETE
의 성공 결과는 종종 200 OK가 아니라 204 No Content (또는 201 Created 리소스가 처음으로 업로드되었을 때)이다PUT
)일반적인 사용 사례는
PUT
요청의 결과로 204를 반환하고 리소스를 업데이트하는 것이다.PUT
요청의 결과로 리소스가 생성되면 201이 대신 반환된다. Content-Range
헤더와 관련 있다.Content-Range
와 Date
헤더를 반드시 포함해야 하며, Etag
와 Content-Location
중 하나의 헤더도 반드시 포함해야 한다.일반적인 사용 사례는
GET
또는 HEAD
방법에 대한 응답으로만 사용하고,GET
또는 HEAD
방법에 대한 응답으로만 설정하고,GET
로 변경하려는 경우 대신 303 “기타”를 사용해야 한다. POST
요청에 대한 응답으로 클라에게 리소스의 위치를 알려주는 것.PUT
또는 POST
의 결과로 반송된다.If-Modified-Since
헤더를 전송한다. (If-None-Match
, If-Modified-From
)Cache-Control
, Content-Location
, Date
, ETag
, Expires
, Vary
가 포함되었을 것이다.Allow
헤더가 포함되어야 한다.GET
와 HEAD
는 사용 불가능해서는 안 되며,Accept
Accept-Charset
Accept-Encoding
Accept-Language
PUT
요청에 대응하여 발생할 가능성이 가장 높다.If-Unmodified-from
또는 If-None-Match
헤더에 의해 정의된 조건이 충족되지 않을 때 GET
또는 HEAD
이외의 방법에 대한 조건부 요청에서 발생한다. Retry-After
)를 반환할 수 있다.If-Match
와 같은 필수 전제 조건 헤더가 누락됨을 의미한다.참고자료
]]>GET
, HEAD
, OPTIONS
메서드는 안전한 메서드로 정의되어있다. TRACE
로 클라이언트 쪽에 공격을 시도하여 credentials을 훔칠 수도 있기 때문에 안전한 메서드에 속하지 않는다.번역에 오역이 있을 수 있습니다..
정의된 의미들이 본질적으로 읽기 전용인 경우, 요청 메소드는 “안전한” 것으로 간주됩니다. 즉, 클라이언트는 해당 리소스에 안전성있는 메서드를 적용한 결과로, origin 서버에 상태변화를 요청하지도 않고, 상태변화를 예상하지도 않는다. 마찬가지로, 안전성 있는 메서드를 합리적으로 사용한다면 origin 서버에서는 어떤 해를 야기하거나 리소스 손실 또는 비정상적인 부담을 예상하지 않는다.
안전한 메소드의 정의로
을 포함시키지 않았다.
중요한 것은 client가 추가젹인 행동을 요구하지 않았고, 그것에 대해 책임을 질 수 없다는 것이다.
예를 들어 대부분의 서버는 메소드에 관계없이 모든 응답이 완료될 때 로그 파일에 액세스하기 위해 요청 정보를 추가하며, 로그 저장소가 가득 차서 서버가 손상될 수 있음에도 불구하고 안전한 것으로 간주된다. 마찬가지로, 웹 상에서 광고를 선택함으로써 시작된 안전한 요청은 종종 광고 계정을 청구하는 부작용을 낳을 것이다.
이 사양에서 정의한 요청 메서드 중 GET, HEAD, OPTIONS 및 TRACE 메서드는 안전하도록 정의되어 있습니다.
안전한 메서드과 안전하지 않은 메서드을 구분하는 목적은 자동 검색 프로세스(스파이더)와 캐시 성능 최적화(프리페치)가 해를 일으킬 염려 없이 작동할 수 있도록 하는 것이다.
또한, 사용자 에이전트는 신뢰할 수 없는 콘텐츠를 처리할 때 안전하지 않은 메서드의 자동 사용에 적절한 제약을 가할 수 있다.
사용자 에이전트는 사용자에게 잠재적 조치를 제시할 때 안전과 안전하지 않은 메서드을 구분하여 사용자가 요청하기 전에 안전하지 않은 조치를 인지할 수 있도록 해야 한다.
효과적인 요청 URI 내의 매개 변수가 action을 선택하는 효과를 가지도록 리소스를 구성하는 경우 action이 요청 메서드의 의미와 일치하는지 확인하는 것은 리소스 소유자의 책임이다.
예를 들어 웹 기반 콘텐츠 편집 소프트웨어는 “page?do=delete”와 같은 쿼리 매개 변수 내의 action을 사용하는 것이 일반적이다.
이러한 리소스의 목적이 안전하지 않은 action을 수행하는 것이라면(GET, HEAD, OPTIONS가 아닌) 리소스 소유자는 안전한 요청 방법을 사용하여 액세스할 때 해당 action을 실행 중지하거나 허용하지 않아야 한다.
그렇게 하지 않으면 자동화된 프로세스가 링크 유지보수, 프리 페치(사전 검색), 검색 색인 구축 등을 위해 모든 URI 참조에 GET를 수행할 때 사이드 이팩트가 발생할 수 있다.
PUT
, DELETE
, TRACE
및 안전한 요청 방법(GET
, HEAD
, OPTIONS
)이 멱등성을 갖는다.번역에 오역이 있을 수 있습니다..
요청 메서드로 해당 방법으로 동일한 요청을 여러번 했을 때, 한 번했을 때와 결과가 같다면 “멱등”으로 간주한다. 이 사양에서 정의한 요청 방법 중에서 PUT, DELETE 및 안전성 있는 메서드가 멱등성을 갖는다.
안전성과 마찬가지로 멱등성은 사용자가 요청한 내용에만 적용됩니다. 서버는 각 요청을 별도로 기록하거나, 수정 관리 기록을 유지하거나 혹은 멱등성을 갖는 요청마다 다른 비멱등성 사이드이팩트들를 구현할 수도 있다.
클라이언트가 서버의 응답을 읽기 전에 통신 장애가 발생할 경우 요청이 자동으로 반복될 수 있기 때문에 멱등성 메서드가 구별된다. 예를 들어 클라이언트가 PUT 요청을 보내고 응답이 수신되기 전에 기본 연결이 닫힌 경우 클라이언트는 새로운 연결을 설정하고 멱등(?) 요청을 다시 시도할 수 있다. 원래 요청이 성공하더라도, 응답은 다를 수 있지만, 요청을 반복하는 것은 의도된 것과 동일한 효과를 낼 것이라는 것을 알고 있다.
안전한 메서드
는 캐시 가능한 것으로 정의한다.GET
, HEAD
, POST
Request methods can be defined as “cacheable” to indicate that responses to them are allowed to be stored for future reuse; for specific requirements see RFC7234. In general, safe methods that do not depend on a current or authoritative response are defined as cacheable; this specification defines GET, HEAD, and POST as cacheable, although the overwhelming majority of cache implementations only support GET and HEAD.
서버에게 리소스를 달라고 요청하기 위해 쓰인다.
요청메세지에 바디 존재 | X |
성공 응답메세지에 바디 존재 | O |
안전성 | O |
멱등성 | O |
캐시 가능? | O |
HTML form에서 사용 가능? | O |
요청
1 | GET /index.html HTTP/1.1 |
응답
1 | HTTP/1.1 200 OK |
안전성과 멱등은 신뢰할 수 없는 네트워크 상의 HTTP를 신뢰할 수 있게 만들어 준다. 만일 GET 요청을 보내고 응답을 못 받았을 경우 그냥 한 번 더 보내면 된다. 이 동작은 안전하다. 먼저 보낸 요청이 벌써 처리되었다 하더라도 서버에 다른 영향은 없다. 마찬가지로 PUT 요청을 보내고 응답을 못 받았다면 단지 한 번 더 동일한 요청을 보내면 된다.
그러나 POST는 안전하지도 않고 멱등도 아니다. 따라서 POST 메소드는 주의해서 사용해야 한다. 출처(행복한 아빠)
GET처럼 행동하지만, 서버는 응답으로 헤더만을 돌려준다.
엔터티 본문은 반환되지 않는다.
이럴 때 사용한다.
요청메세지에 바디 존재 | X |
성공 응답메세지에 바디 존재 | X |
안전성 | O |
멱등성 | O |
캐시 가능? | O |
HTML form에서 사용 가능? | X |
요청
1 | HEAD /index.html HTTP/1.1 |
응답
1 | HTTP/1.1 200 OK |
서버에 문서를 쓴다….(?)
PUT 메서드의 의미는
요청메세지에 바디 존재 | O |
성공 응답메세지에 바디 존재 | X |
안전성 | X |
멱등성 | O |
캐시 가능? | X |
HTML form에서 사용 가능? | X |
요청
1 | PUT /joy.txt HTTP/1.1 |
응답
1 | HTTP/1.1 201 Created |
요청메세지에 바디 존재 | O |
성공 응답메세지에 바디 존재 | O |
안전성 | X |
멱등성 | X |
캐시 가능? | 새 정보가 포함되었을 때만 |
HTML form에서 사용 가능? | X |
요청
1 | POST /inventory-check.cgi HTTP/1.1 |
응답
1 | HTTP/1.1 200 OK |
요청이 의도한 요청/응답 연쇄를 거쳐가는지 검사할 수 있다.
중간 어플리케이션이 여러 다른 종류의 요청들을 일관되게 다룬다고 가정하는 문제가 있다.
요청메세지에 바디 존재 | X |
성공 응답메세지에 바디 존재 | X |
안전성 | X |
멱등성 | O |
캐시 가능? | X |
HTML form에서 사용 가능? | X |
클라 요청
1 | TRACE /product-list.txt HTTP/1.1 |
프록시 요청
1 | TRACE /product-list.txt HTTP/1.1 |
서버 응답
1 | HTTP/1.1 200 OK |
프록시 응답
1 | HTTP/1.1 200 OK |
Allow
필드를 포함해서 돌려준다.Access-Control-Request-Method
Access-Control-Request-Headers
Origin
요청메세지에 바디 존재 | X |
성공 응답메세지에 바디 존재 | O |
안전성 | O |
멱등성 | O |
캐시 가능? | X |
HTML form에서 사용 가능? | X |
요청
1 | OPTIONS * HTTP/1.1 |
응답
1 | HTTP/1.1 200 OK |
요청메세지에 바디 존재 | ▲ |
성공 응답메세지에 바디 존재 | ▲ |
안전성 | X |
멱등성 | O |
캐시 가능? | X |
HTML form에서 사용 가능? | X |
요청
1 | DELETE /joy.txt HTTP/1.1 |
응답
1 | HTTP/1.1 201 Created |
PUT
과 달리 비멱등성을 가진다.PATCH
의 사용 여부는 Accept-Patch
로도 가능하다.PUT
은 문서 자체의 교체만을 허용한다.PUT
으로 수정할 JSON 일부분을 보낼 때, 보낸 필드 이외의 필드는 null
혹은 초기화 처리가 된다.PATCH
로 수정할 JSON 일부분을 보낼 때, 해당 필드만 수정된다.요청메세지에 바디 존재 | O |
성공 응답메세지에 바디 존재 | O |
안전성 | X |
멱등성 | X |
캐시 가능? | X |
HTML form에서 사용 가능? | X |
요청전 데이터
1 | { |
PATCH
요청
1 | PATCH /api/user/123 HTTP/1.1 |
PATCH
결과
1 | { |
PUT
요청
1 | PUT /api/user/123 HTTP/1.1 |
PUT
결과
1 | { |
잘 모르겠다.
CONNECT
메소드는 요청된 리소스와 양방향 통신을 시작한다. CONNECT
메소드를 사용하여 SSL(HTTPS)을 사용하는 웹 사이트에 액세스 할 수 있다. 요청메세지에 바디 존재 | X |
성공 응답메세지에 바디 존재 | O |
안전성 | X |
멱등성 | X |
캐시 가능? | X |
HTML form에서 사용 가능? | X |
요청
1 | CONNECT server.example.com:80 HTTP/1.1 |
LOCK
- 사용자가 리소스를 잠글 수 있게 해준다.MKCOL
- 사용자가 문서를 생성할 수 있게 해준다.COPY
- 서버에 있는 리소스를 복사한다.MOVE
- 서버에 있는 리소스를 옮긴다.확장메서드를 다룰 때는 ‘엄격하게 보내고 관대하게 받아들여라’라는 오랜 규칙에 다르는 것이 가장 좋다.
참고자료
]]>HTTP 메세지는 HTTP 메세지 간에 주고받은 데이터의 블록들이다
인바운드로 이동
/ 아웃바운드로 이동
요청
버전은 프로토콜 버전
1 | <메서드> <요청 URL> <버전> |
응답
1 | <버전> <상태 코드> <사유 구절> |
아스키 문자열 ?
미국정보교환표준부호(영어: American Standard Code for Information Interchange), 또는 줄여서 ASCII( /ˈæski/, 아스키)는 영문 알파벳을 사용하는 대표적인 문자 인코딩이다. 아스키는 컴퓨터와 통신 장비를 비롯한 문자를 사용하는 많은 장치에서 사용되며, 대부분의 문자 인코딩이 아스키에 기초를 두고 있다.
아스키코드
10 LF ( Line Feed => 다음 줄로)
13 CR ( Cariage Return => 제일 처음 칸으로)
요청 메세지는 서버에게 리소스에 대해 무언가를 해달라고 부탁한다.
요청 메세지는
메서드
: 서버에서 어떤 동작이 일어나야 하는지 설명해주는URL
: 동작에 대한 대상을 지칭HTTP 버전
: 클라가 어떤 HTTP버전으로 말하고 있는지모든 필드는 공백으로 구분된다.
헤더
만 가져온다.저장
한다.추적
한다.버전 번호는 HTTP로 대화하는 어플리케이션들에게
대화 상대의 능력과 메세지의 형식에 대한 단서를 제공하기 위한 것이다.
응답 메세지는 수행 결과에 대한
응답 메세지의 시작줄, 즉 응답줄은
HTTP버전
상태코드
사유구절
모든 필드는 공백으로 구분된다.
Controls
, Conditionals
, Content Negotiation
, Authentication Credentials
, Request Context
로만 분류되어있다.Controls
: 요청의 특정 처리를 지시하는 헤더들Conditionals
: 조건부 헤더Content Negotiation
: 협상 헤더Authentication Credentials
: 권한 헤더Request Context
: 요청 정보 헤더URL(Uniform Resource Locator)은 인터넷 리소스를 가리키는 표준이름이다.
URL은 전자정보 일부를 가리키고, 그것이
어디에 있고
어떻게 접근할 수 있는지 알려준다.
URL을 사용하면 리소스를 일관된 방식으로 지칭할 수 있다.
대부분의 URL은 동일하게 스킴://서버위치/경로
구조로 이루어져있다.
URL은 통합 자원식별자 혹은 URI라고 불리는 더 일반화된 부류의 부분집합이다.
URI는 URL과 URN으로 구성된 종합적인 개념이다.
1 | <스킴>://<사용자이름>:<비밀번호>@<호스트>:<포트>/<경로>;<파라미터>?<질의>#<플래그먼트> |
:
를 사용한다.기본값
IEUser
(익스플로러), chrome@example.com
(크롬)1 | ftp://anonymous:my_passwd@ftp.prep.ai.mit.edu/pub/gnu |
Host
Port
/
를 기준으로 경로조각으로 나누니다.;
문자로 구분하여 URL에 기술한다.개인적으로 지금까지 이런 형식의 URL을 본적이 없어서, 검색해보니
이런 형식을 Matrix parameter라고 불리며, 쿼리스트링과의 차이점은 아래와 같다고 나왔다.
( 관련링크 Query vs. Matrix Params )
아직 proposal state에 존재하며, 웹 표준이 아니라고 한다.
(관련 링크 w3-MatrixURIs )
&
로 나뉜 이름=값
쌍 형식의 쿼리스트링을 원한다특정 문자 사용 금지.
알파벳 이외의 문자도 포함될 수 있도록 이스케이프 기능 추가
US-ASCII
문자 집합을 사용해 왔다.이런 경우를 지원하기 위해서 이스케이프 문자열을 쓸 수 있게 설계하였다.
URL에 있는 안전하지 않은 문자들을 표현할 수 있는 인코딩 방식이 고안되었다.
인코딩은 이스케이프 문자로 바꿔준다.
%
로 시작해 ASCII 코드로 표현되는 두개의 16진수 숫자로 이루어져있다.예시
%
: 인코딩 이스케이프 토큰/
: 경로 컴포넌트 세그먼트를 나누는 용도.
: 경로 컴포넌트에서 사용..
: 경로 컴포넌트에서 사용#
: fragment 컴포넌트에서 사용?
: 쿼리파라미터 컴포넌트에서 사용;
: 매트릭스 파라미터 컴포넌트에서 사용:
: 스킴, 사용자 이름/비밀번호, 호스트/포트의 구획문자로 사용$
: 미리 선점되었다.+
: 미리 선점되었다.{
}
|
\
~
[
]
・
<
>
"
0x00-0x1F
0x7F
> 0x7F
웹 클라이언트는 몇몇 단축 URL을 인식하고 사용한다.
URL은 2가지로 나뉜다.
브라우저 같은 어플리케이션은 상대URL과 절대URL 간에 상호 변환을 할 수 있어야 한다.
기저 URL 찾는 방법
<base>
HTML 태그를 기술할 수 있다. (base)상대 URL과 기저을 각각의 컴포넌트 조각으로 나누는 것이다.
URL분해하기 = URL 파싱하기
변환을 위해서 특정 알고리즘을 사용한다.
이 알고리즘은 상대URL을 절대URL 형태로 변환한다.
호스트명 확장
yahoo.com
⇒ www.yahoo.com
을 만든다.히스토리 확장
스킴 | 설명 | 예 |
---|---|---|
http | HTTP스킴이다. 포트값이 생략되어 있으면 기본값은 80이다. | http://feel5ny.github.io |
https | 암호화하기 위해 넷스케이프에서 개발한 보안 소켓 계층(SSL)을 사용한다. 기본포트는 443 | https://feel5ny.github.io |
mailto | 이메일 주소를 가리킨다. RFC 822 | mailto:joe@joes-hardware.com |
ftp | 파일 전송 프로토콜. FTP는 웹과 URL이 출현하기 전부터 있었다. | ftp://anonymous:joe%40joes-hardware.com@prep.ai.mit.edu:21/pub/gnu/ |
rtsp, rtspu | 실시간 스트리밍 프로토콜(Real Time Streaming Protocol), rtspu에서 u는 리소스를 읽기 위해서 UDP 프로토콜이 사용됨을 뜻한다. | rtsp://www.joes-hardware.com:554/interview/cto_video |
file | 주어진 호스트 기기에서 바로 접근할 수 있는 파일들을 나타낸다. | file//OFFICE-FS/policies/casual-fridays.doc |
news | RFC 1036에 정의된 바와 같이 특정 문서나 뉴스 그룹에 접근하는데 사용한다. | news:rec.arts.startrek |
telnet | 대화형 서비스에 접근하는데 사용한다. | telnet://slurp:webhound@joes-hardware.com:23/ |
참고자료
]]>웹 어플리케이션은 사용자에게 어플리케이션을 보여주기 위해,
사용자가 어플리케이션에 입장할 시점에
서버에서 데이터(소스)를 받아와야한다.
어플리케이션은 서버에게 어떻게 데이터를 받아오는지 http를 모른다고 생각하고 상상해보자.
우선 데이터가 존재하는 서버의 위치부터 파악 해야한다.
Host
위치를 파악했다면 클라이언트와 서버의 연결이 필요하다.
TCP/IP 커넥션, port
연결이 이루어졌다면, 서버에게 원하는 바를 요청해야한다.
HTTP: HTTP 프로토콜을 통해 요청/응답메세지를 보낸다.
요청이나 응답에서 어떤 데이터를 보내고, 받았는지
데이터의 위치, 종류를 알아야, 클라이언트에서 해석할 수 있다.
Content-Type, URI
특정상황에선 통신을 원할하게 해주는 다른 요소들이 필요하다.
HTTP의 기반 시스템의 구성요소
이 모든 과정에 필요한 HTTP에 대해서 알아보고, 과정 순서대로 톺아보려고한다.
HTTP는 WWW 상에서 정보를 주고받을 수 있는 프로토콜이다.
주로 HTML 문서를 주고받는 데에 쓰인다.
TCP와 UDP를 사용하며, 80번 포트를 사용한다.
인터넷의 멀티미디어 배달부
웹브라우저, 서버, 웹 어플리케이션 모두 HTTP (HyperTest Transfer Protocaol)을 통해 서로 대화한다.
HTTP는 현대 인터넷의 공용어이다.
HTTP는 신뢰성 있는 데이터 전송 프로토콜을 사용하기 때문에, 데이터가 지구 반대편에서 오더라도 전송 중 손상되거나 꼬이지 않음을 보장한다.
웹 서버는 HTTP프로토콜로 의사소통하기 때문에 보통 HTTP서버라고 불린다.
프로토콜이란?
사람과 사람이 통신할 때 서로 이해할 수 있는 언어, 공용된 언어를 사용해 전세계 모든 사람과 대화 할수 있다라고 하면,
컴퓨터와 컴퓨터도 서로 이해 할 수 있는 언어, 공용된 언어를 사용 해야 한다는 것인데 이것이 바로 프로토콜(Protocol) 입니다.
데이터를 갖고 있는 서버의 위치를 알기 위해서 해당 서버의 주소, 즉 ip주소와 포트번호를 알아야한다.
뒤에 나올 TCP/IP 커넥션에 필요한 IP주소와 포트번호에 대한 내용이다.
HTTP 클라이언트가 서버에 메세지를 전송할 수 있게 되기 전에,
인터넷 프로토콜 주소와 포트번호를 사용해
클라이언트와 서버 사이에 TCP/IP 커넥션을 맺어야 한다.
TCP에서는
서버 컴퓨터에 대한 IP주소와
그 서버에서 실행 중인 프로그램이 사용중인 포트번호가 필요하다.
( 전화기로 치면, IP주소는 전화번호, 포트번호는 전화 걸고자 하는 상대방이 쓰는 번호 )
IP주소와 포트번호는 어떻게 알 수 있을까? ⇒ URL을 이용하면된다.
1 | http://207.200.83.29:80 |
1 | 1. 웹 브라우저는 서버의 URL에서 호스트 명을 추출한다. |
1번부터 4번까지 알아보았다.
TCP 커넥션을 통해서 어떻게 데이터가 넘어가는지 알아보자.
1 | telnet feel5ny.github.io 80 👈👩💻 |
서버와 대화하는 방식을 알아야한다.
클라이언트와 서버의 대화는
주로 사람이 대화하듯이 말을 전달하고,
응답받는 모양으로 구성되어있다.
즉, HTTP 트랜잭션은 요청 명령과 응답 결과로 구성되어있다.
서로가 이해하는 언어로 사용해야하기때문에 HTTP 메세지라고 불리는 정형화된 데이터 덩어리를 이용해 이루어진다.
클라이언트는 사용자의 요청에 따라 데이터를 처리하기위해 서버에게 특정 액션을 설명해줘야한다.
HTTP 에서 흔히 쓰이는 5가지 메서드
흔히 쓰이는 상태 코드 몇가지.
HTTP 메세지
웹 클라이언트 ⇒ 웹 서버 : 요청 메세지
웹 서버 ⇒ 웹 클라이언트 : 응답 메세지
이 외의 다른 종류이 http 메세지는 없다.
http 요청과 응답 메세지의 형식은 굉장히 비슷하다.
:
구분되어 있는 하나의 이름과 하나의 값으로 구성된다.이제 서버와 어떻게 대화하는지를 알게 되었다.
특정 데이터를 특정 액션(메서드)을 해달라는 요청을 하는 방법을 알게되었는데,
특정 데이터라는 건 어떻게 서버가 알게 해야할까.
우선 데이터가
어디에 있는 어떤 컨텐츠인지를 어떻게 알까. URI개념을 이용하면 된다.
Uniform Resource Identifier = 통합 자원 식별자
아래 URI를 분석해보면,https://feel5ny.github.io/2019/07/07/Joylog_003/
1 | 1. https:// http 프로토콜을 사용하라 |
URI에는 2가지가 있다.
Uniform Resource locator = 통합 자원 지시자
https://
http://
스킴과 스키마의 차이점
스키마(schema)는 계획이나 도식을 가리키는 영어 낱말로, 다음을 가리킨다. 참고로 스킴(scheme)은 스키마와 거의 같은 의미로 쓰이나, 보통 스키마가 대략적인 계획이나 도식을 뜻하는 데 비해 스킴은 구체적이고 확정된 것을 말한다.
feel5ny.github.io
/2019/07/07/Joylog_003/
잘 모르겠다.
Uniform Resource name = 통합 자원 이름
어디에 있고, 어떤 이름을 갖는 파일인지를 알아보는 방법을 알아봤으니,
해당 컨텐츠가 어떤 종류의 타입인지를 알야아한다.
인터넷은 수천 가지 데이터 타입을 다루기 때문에
HTTP는 웹에서 전송되는 객체 각각에
신중하게 MIME 타입이라는 데이터 포맷 라벨을 붙인다.
MIME = multipurpose Internet Mail Extensions = 다목적 인터넷 메일 확장
웹 서버는 모든 HTTP 객체 데이터에 MIME 타입을 붙인다.
MIME 타입은 사선 /으로 구분된 주 타입과 부타입으로 이루어진 문자열 라벨이다.
1 | 주타입/부타입 (primary object type / specific subtype) |
종류
text/html
text/plain
image/jpeg
image/gif
video/quicktime
application/vnd.ms-powerpoint
1991년 HTTP 프로토타입 HTTP/0.9
문제점
상황
처음으로 널리 쓰이기 시작한 HTTP 버전
상황
지원
HTTP 설계의 구조적 결함 교정,
두드러진 성능 최적화,
잘못된 기능제거에 집중했다.
1.1 성능 문제를 개선하기 위해
구글의 SPDY 프로토콜을 기반으로 설계가 진행중인 프로토콜이다.
@2021-02-12 추가
특정상황에 효율적인 처리를 위해 만들어진 HTTP 구성 요소 개념
클라이언트와 서버 사이에 위치한 HTTP 중개자
서버와 클라이언트 사이에 중계자로서
대리로 통신을 수행하는 것을 가리켜 ‘프록시’,
그 중계 기능을 하는 것을 ‘프록시 서버’라고 부른다.
예시
많이 찾는 웹페이지를
클라이언트 가까이에 보관하는 HTTP 창고
다른 어플리케이션과 연결된 특별한 웹 서버
예시
HTTP 통신을 전달하기만 하는 특별한 프락시
예시
자동화된 HTTP 요청을 만드는 준지능적 semi-intelligent 웹클라이언트
예시
참고링크
]]>2019 다짐 글 ( 안녕 2018, 안녕 2019 ) ➔
2019년 다짐 글을 쓸 당시 기본 실력을 키우자 라는 글을 쓸 때의 느낌은.. 참 가벼웠던 거 같다.
두루뭉술했고, 구체적이지 않아서, 어쨌든 자바스크립트 공부겠지.
, 특정 책 하나 더 공부하지
라는 정도로만 느꼈었다. 때문에 목표가 구체적이지 않아서, 동기도 강하지 않았다.
그런 와중에 회사에서의 상반기 경험으로 기본 실력의 범위를 다시 한번 정의할 수 있었다.
상반기 때는 기본 실력이 왜 중요한지, 구체적으로 느낄 수 있는 여러 가지 사건이 있었다. 프론트엔드 개발자로서의 언어의 기본 지식도 포함되지만, 서비스(어플리케이션)을 만들고 배포하고 유지 보수하는 상황에서 필요한 지식도 기본 실력에 포함시켜야 한다고 생각했고, 그 지식의 더 원론적인 레벨에 있는 내용도 더 많이 공부해야겠다고 생각이 들었다.
상반기를 가볍게 본다면 자바스크립트의 es6 문법에 대해서 좀 더 공부했고, 실무에서도 활용해보려고 노력했다. 리액트 등의 프레임워크 의존도도 벗어나보려고 스터디도 참여해 보았고, 알고리즘 공부도 조금씩 진행했다.
이 글의 하반기 다짐 글에는 기본 실력 키우기의 소제목을 구체적으로 정의해서 실천해야겠다.
디자인 시스템의 이해도를 높이기 위해서
개인적으로는 코드 레벨에서 구조화정도까지만 작업이 되었고,
외부적으로는 디자인 시스템에 대해서 사내발표를 진행했다.
디자이너와 함께하는 프로젝트에서 효과가 발휘되는 시스템인데, 현재 나의 상황에서는 사내의 프로젝트 정도가 디자인 시스템을 적용할 수 있었다. 이 시스템의 구축은 디자이너와의 협업도 필요한 부분이지만, 사전에 이 시스템이 개발자들에게 어떤 생산성을 가져다주는지에 대해서 팀원들에게 먼저 알려줄 필요가 있다고 생각이 들었다.
개인적인 포트폴리오 작업을 이루지 못했다.
너무 무겁게 생각해서 시작을 못한 것도 큰 이유인 것 같다.
그래서 이번엔 진짜 가볍게! 어플리케이션 수준 말고, 우선 게츠비 혹은 hexo 블로그 테마를 만드는 것을 1차 목표로 다시 잡았다.
또 다른 목표는 회사일과 내 생활의 균형을 맞춰가면서 작은 것 하나라도 만들어보는 것.
작년 11월부터 글또 2기에 참여하고 있었다. 4월에 마무리를 지으면서, 총 17개의 글을 작성하였다. 개수는 큰 의미가 없지만.. 1기에 비해서는 글의 퀄리티나, 글감의 종류는 많이 아쉬운 편이다.
나름 그래도 반강제적으로 공부할 수 있도록 만들어준 것에 감사하다. 2주일마다 주말에 컴퓨터 앞에 앉을 수 있도록 도와주는 고마운 모임이다.
2기 마무리 때는 케어랩스 본사로 초대 드렸다. 타이밍이 좋지 않아 엘리베이터 공사 중에 모임 날짜가 잡혀서 반강제로 10층까지 계단 운동을 할 수 있도록 만들어드렸다 😂
좋아하는 코드 스피츠 강의를 2개 참여했다.
1번 수업이 진짜 재밌었다. 그 당시 어플리케이션에서 역할별로 레이어를 쪼개는 아키텍처에 대해서 적용해 보려고 고민을 많이 하고 있었는데, 고민만큼 의문도 컸었다. 사실 레이어를 쪼개지 않을수록 그 순간의 작업량은 쪼갰을 때보다는 확실히 적고, 단순하기 때문이다. 그런 의문이 들 때 이 수업을 들었는데, 레이어링이 후에 어플리케이션의 복잡도를 낮출 수 있도록 도와준다는 내용을 듣고, 확신을 얻고 작업할 수 있게 되었다. 물론 자바스크립트로 게임을 만드는 것에도 엄청 재밌었다.
코드 스피츠 수업은 수업 자체가 너무 알차기 때문에 정리하는 데만 해도 시간이 많이 걸리는 수업이다. 단점이라면, 정리만으로도 마치 공부를 다했다는 착각이 들기 때문에 반드시 배운 내용을 덮어두고 의식적으로 실습을 해봐야지 배운 내용을 리마인드 시키면서 체화시킬 수 있는데, 정리 이후의 시간에 투자를 많이 못 했던 것 같다. 물론 작년까지만 해도 코드 스피츠 수업 내용 자체를 이해하기위해 많은 노력을 했었어야 했는데,
이제는 조금? 작년보다는 받아들이는데 시간이 조금 줄어든 것 같다… 의식적 실습에 더 투자해보자.
코드골프 수업 때는 사실 이 영역은 배워야 할 부분이 너무 많다는 것이 느껴져서 중도 포기를 하게 되었다. 지식부터 접근할 때의 생각 방법까지.. 이 수업 시간에는 매 순간이 놀라움이었다. (정말 매번 수업 때마다 헐?
을 난무)
아직까지는 따라가기 버겁다고 생각이 들어서 keep 해 놓았고, 티끌 모아 태산 전략으로 아주 조금씩 공부해 보려고 한다.
프로그래머스에서 진행하는 바닐라 자바스크립트 스터디에 참여했다. 평소 사내에서는 리액트 위주로 작업을 하기 때문에 따로 사이드 프로젝트를 하지 않는 이상,(사실 사이드 프로젝트에서도 바닐라는 잘 안 쓰게 될 거 같다..) 혹은 코드 스피츠 같은 바닐라 자바스크립트 기반의 수업에 참여하지 않는 이상 바닐라로 실습하는 환경을 만들기 힘들었기 때문에 감을 잃지 않게 수강하게 되었다. 수업방식은 과제의 명세를 다 구현하고, pr을 올리면 서로가 코드 리뷰를 해주는 방식이다.
근데 생각보다 코드 리뷰에 대해서 너무 좋은 인상을 얻게 되었다. 사실 솔직하게는 제대로 된 코드 리뷰를 처음 받아본 것 같았다. 이렇게 서로 다른 스타일을 갖고 있는 많은 인원의 코드 리뷰를 받을 수 있다는 것과, 서로 간의 커뮤니케이션 방법에 대해서도 다양하게 접할 수 있어서 협업 시 지녀야 할 스킬에 대해서 배울 수 있었다.
사실 이 워크샵 때 진행했던 모든 aws 서비스를 전부 이해하진 못했다. 하루 만에 8가지 서비스 맛보기니 ㅎㅎ 뭔가 aws에는 이렇게나 많은 서비스가 있고, 이 기능을 너희가 써주면 좋을 거 같아! 느낌의 수업이었다. 수업도 아니고.. 거의 튜토리얼 형 수업이었다. 집에서 몇 번 하면서 아 이런 게 있구나 하는 정도로 복습해 보려고 한다. 간단한 토이 프로젝트에 써보면 재밌을 거 같긴 하다.
이모에서 번역팀을 모집해서 참여했다. 나름 테스트 번역도 통과해서 비개발 번역팀에 속하게 되었고, 첫 번째 번역은 이모지 글에 대한 번역이었다. 하나의 글을 함께 번역하는데, 데드라인을 딱히 정하지 않고 있어서 다른 분들은 아직도 .. 진행 중이다… (뭔가 이 모임은 마무리 지어야겠다..)
굿닥은 매주 사내 테크톡을 진행한다. 개발자들이 매주 돌아가면서 자유롭게 발표를 하는 형식으로 진행하는데, 상반기 때는 3번의 발표를 진행했다. 대부분이 팀 내에 공유가 되면 좋을 주제들 위주로 진행했다.
올해 초, 패캠 수료생들의 모임에서 발표를 진행했다. 1년 동안 무엇을 실수했고, 그로 인해서 무엇을 배웠냐에 초점을 맞춰서 발표를 진행했다. 개인적으로 1년을 회고할 수 있어서 좋았다.
이제 막 커리어를 시작할 분들을 위한 세미나에서 발표 제안이 왔다.
제일 도움이 많이 되었던 기록하기
에 대해서 발표해보려고 한다. ➔
2기 때 글또를 하면서 작성했던 글의 종류이다. 2기 때 글의 카테고리를 이렇게 정리했었다.
그때 당시에는 “1번 > 2번, 3번
비율로 쓸 예정이다.” 라고 했었는데, 확실히 예상대로 ㅎㅎ 1번을 많이 작성하₩긴 했다. 3번 4번은 아예 작성하지를 못했다. 4번은 상반기에는 딱히.. 세미나가 없었다. 사실 표만 예매하고 가지 않아서 쓸 후기가 없었다. 3번은 약간 여유가 있을 때 쓰게 되곤하는데, 상반기에는 여유가 없었다. 사내에 큰 배포도 있었고, 야근도 종종 하고 이것저것 일을 벌여놔서 그런 게 아닌가 싶다.
사실 상반기에는 자바스크립트 자체 공부는 많이 못 한 거 같다. 물론 수업을 이것저것 듣긴 했지만.. 개인적으로는 이것저것 삽질을 통해 알게 된 깨달음 정도..만 있었던 거 같다. (반성반성)
클린 아케텍처에 한때 꽂혔었다. 레거시 코드를 양성하고 싶지 않은 강한 마음으로, 복잡도를 낮출 수 있는 여러 가지 설계 방법에 대해서 고민했었고, 클린 아키텍처에 관심을 갖게 되었다. 기존 알고 있던 아키텍처보다 조금 더 비즈니스 로직을 이상적으로 분리할 수 있었지만, 레이어가 많이 쪼개짐에 따라 관리해야 할 레이어도 많이 생겨난다는 상황은 또 다른 고민을 만들긴 했다.
남자친구와 유튜브 컨텐츠를 제작해보려고 했다. 계정도 만들고 촬영도 했는데 편집을 아직 못했다. 유투브 콘텐츠는 확실히 자극적인 콘텐츠로 만들어야 하는데, 자극적인 카피를 뽑는 것부터, 생소한 주제라든지, 재밌게 편집해야 하는 부분이라든지, 지금까지 만들었던 콘텐츠들과는 다르게 생각해야 하는 면이 있어서 만들 때부터 고민이다.
매년 한 해의 다짐 리스트에 있던 운동을 시작해보았다. 체력이 너무 떨어진 것 같아서 시작한 것도 있다.
사실 다른 핑계들 때문에 시작하지 못할 수 있었는데, 회사에서 필라테스 하시는 분들의 이야기도 듣고, 주변 지인들의 적극적인 권유로 시작하게 되었다. 2달 반 정도 진행되고 있는데, 선생님이 자세가 괜찮다고 엊그제 말씀해주셔서 기분이 좋은 상태다! 필라테스도 알아야 할 용어가 너무 많아서, 선생님은 단어만 말하면 내가 딱딱 그 자세를 하길 원하시는데, 바로바로 기억해내지 못했다. 몇 번을 그렇게 되니 안되겠다 싶어 한번 정리나 해보자 해서, 요약 그림을 만들었는데, 한두 번하다가 그만뒀다.
상반기를 회고해보니 공부 비율보다는 딴짓 비율이 높은 것 같다.
좀 더 기본 지식 딥한 공부 + 체화하는 실습시간을 갖는 걸 목표로 잡고 계획해봐야겠다.
맨 처음에 말했던 것처럼 블로그 테마 하나 내보기! 지금까지 블로그 하면서 불편했던 부분을 개선해서 올리려고 한다.
아무래도 1번 > 2번 > 3번, 4번
순으로 작성할 것 같다. 특히 이번 삽질하면서 작성하고 싶은 글이 너무 많아서 2번의 비율이 예전보다 높지 않을까 생각된다.
우선 이번 기수 때 12개의 글을 기본 작성해야 하니
이렇게 개수는 필수로 두고 작성해보자!
코드스피츠 강의 정리록
생소한 도메인으로 배우는게 좋다.
익숙한 도메인들은 익숙한 처리방법으로 처리하기때문에 객체지향을 배우기 어렵다.
때문에 80기는 게임을 통해서 진행할 예정.
1 | const Block = class { |
아키텍처는 코드에 가질 수 있는 역할과 가질 수 없는 역할,
기질 수 있는 책임과 가질수 없는 책임을 명시할 수 있고,
그것으로 코드가 바른지 안바른지 판단하는 기준표가 된다.
- 기존 모델에서 지금 아키텍처와 안 맞는 부분을 지목할 수 있다.
1 | 👉 const data = []; |
= 모든 연산을 data를 갖고 하려고 한다.
일반적으로 프로시저로 짜면 메모리를 적게 사용하게 된다.
2차원 배열에 들어가는데, 블럭에 X값 Y값이 들어가있나?
객체지향은 내 할일이 아니면 위임하는 것이다.
1 | const selected = [], getBlock = (x, y) => {...} |
selected를 사방에서 직접 컨트롤하고 있다.
selected도 블럭이 선택되어있는지 아닌지에 대한 지식이기 때문에
Block의 지식이다.
우리는 완전히 독립되어있는 어떤 데이터를 바라보고 있는
프로시저를 짜서 해결하려고 한다.
끊임없는 상태에 대한 변화의 책임을
블럭이 갖고 있어야한다.
1 | const Block = class { |
👇👇👇
1 | const UTIL = { |
1 | interface IItem { |
싱글 노드 링크드 리스트가 완성되었다.
item 객체가 이 이상을 알게 되면, 권한 위반이 된다.
밖에는 캡슐화 된 메소드로 대화한다.
좀 더 어려운 책임을 바라보게 하자.
1 | const Item = class { |
selectedList에 포함되어있냐 아니냐를 판단하는 메소드
책임 범위를 축소하면 연산을 많이하게 된다.
객체지향에서는 기본적으로 배열같은 어그리게이션(집합)을 쓰는 경우가 거의 없다.
배열을 링크드 리스트로 치환한 것이다.
알고리즘의 태반은 자료구조로 되어있고,
자료구조의 태반은 다시 또 알고리즘으로 돌아가게 되어있다.
항상 메모리와 연산은 교환할 수 있다.
나의 인접 셀을 파악하는 것도 나의 권한이다.
우리가 책임을 부여하고 싶으면, 권한을 부여해야한다.
두개가 어긋나면 둘중 하나가 깨진다.
this
라는 내부상태의 은닉되어있는 상태를 사용하고 있느냐,얼만큼 캡슐화되어야하는지는 대상에 따라 다르다.
]]>내가 만약 프로그램을 짜서 공개되는 코드도 마지막에 은닉과 캡슐화를 처리하는 단계는 항상 머리속에 짱구를 그려야한다.
코드스피츠 강의 정리록
생소한 도메인으로 배우는게 좋다.
익숙한 도메인들은 익숙한 처리방법으로 처리하기때문에 객체지향을 배우기 어렵다.
때문에 80기는 게임을 통해서 진행할 예정.
저번시간의 프로시저 프로그래밍 복습
복잡성이 폭발하면 ? => 버려야합니다.
많은 사람들의 요건추가와 변화로 엔트로피가 꾸준히 증가한다.
엔트로피를 증가시키는 것을 최대한 둔화시켜야한다.
프로그래밍 세계에서 엔트로피가 언제 증가하는지 알아가는 것이 우리 스터디에서 배워야할 것.
많은 장치로 엔트로피의 증가를 막을 수있다.
아무리 막아도 내년되면 다시 짜야한다.
잘못짠 프로그램은 엔트로피가 급격하게 증가해서 빨리 버리게 된다.
잘짠 프로그램도 버려야한다.
엔트로피 증가방향을 컨트롤해서 완화시키고
복잡한 환경이나 여러가지 변화상황을 잘 받아들일 수 있는 구조를 짜는것을
디자인이라고 하고
아키텍처라고 한다.
엔트로피 증가를 막으려고.
객체지향에서는 어떻게 앤트로피 증가를 막느냐.
역할이라는 것으로 분리해서 막는다.
변화율을 기준으로 역할을 분리해서 역할별로 객체들을 만들고 싶은데,
그렇게 하기에는 우리가 해결해야 하는 문제가 너무 큰 덩어리로 되어있는 문제라는 것이다.
사람은 한꺼번에 복잡성 제어를 못 하기 때문에 복잡성 폭발한 프로그램은 버리게 된다.
너무 복잡한 것은 분석할 수 없다.
복잡한 문제는 나눠서 분석해야지만 분석할 수 있다.
복잡한 문제를 나눠서 분석하기 위한 도구를 추상화 도구라고 한다.
(다른 글)
분류를 통해서 계속 나눠가면
상쇄 적인 부분만 하나씩 정복해나가면 전체를 이해할 수 있다는 개념
기억해야만 할 것을 정리하면 모델링이 된다.
데이터에 의존하고 있는 프로시저가 데이터의 변화를 따라갈 수 없기 때문에 프로시저 프로그램들이 에러가 나는 것이다.
우리가 필요해서 묶어주는 것
(feat. 마틴 파울러의 앤터 프라이즈 디자인 패턴 책)레이어라는 방법을 사용한다.
레이어는 일종에 카테고라이즈에 가깝다.
먼저 크게 분리한다.
client ←→ server
presentation ←→ doman ←→ data source
레이어안에는 레이어의 전체적인 레이어 가이드들을 지키고 있는 수많은 레이어들이 존제한다.
인메모리에서 레이어를 나누어보자.
레이어를 나누는 눈이 필요하다.
게임의 실체는 어디일까?
실체는 호스트 코드.
수업 시간에는 아키텍처를 공부하기 위해 반대로 짜볼 것이다.
함수 호출 하는 방식으로 다른 레이어와 소통한다. 모든 레이어와 소통.
베이스 클래스와 구상 클래스의 관계는 상속되거나 소유된다.
뷰가 인터렉션을 할 때 컨트롤러에게 위임하는데
컨트롤러에게 뷰의 책임을 위임하지 않을 것이다.
뷰가 컨트롤러에 그냥 위임하게 되면 컨트롤러에 뷰의 사정이 들어가게 된다.
(네이티브 분리가 안 된다. ex_ dom을 컨트롤하는 로직 등등..)
why?
메세지는 중립적인 역할
뷰도 혼자서 전부 처리하기에 힘들기때문에
서브뷰를 만들어서 그림그리는 체계를 나눠준다.
최종적으로 만들 것은 구상서브뷰와 구상모델을 만들게 된다.
div
가 될 것이고section
뷰가 될 것이다.베이스 클래스 까지는 인메모리 객체이다.
네이티브 지식이 하나도 나오지 않는다. 구상 클래스만 네이티브 지식을 갖게 된다.
개인 삽질 정리록
개인이 접한 문제를 해결했던 경험을 바탕으로 적은 글이므로,
오류가 있는 부분은 댓글로 부탁드립니다
맥OS에서 프론트 개발을 하면 종종 IE 디버깅을 해야할때가 있다. ( 버리고 싶은 IE 🌎 )
virtual박스나 가상머신 파일 다운로드 시간이 걸리므로 미리미리 셋팅해두면 좋다.
여러가지 다른 솔루션이 있겠지만 ( Hyper-V, VirtualBox, Parallels ),
이번 글에서는 오라클에서 제공하는 버추얼박스
를 활용하여
IE 디버깅을 하는 방법에 대해서 간단하게 적어보려고한다.
튜토리얼성 글이다.
virtual박스는 오라클에서 만든 가상머신 솔루션이다.
하드웨어를 소프트웨어적으로 구현해서
그 위에서 운영체제가 작동하도록하는 기술이다. (출처)
설치는 간단하다 -! 시간만 걸릴뿐..
가상머신이 실행되고 우리가 설치한 windowOS가 실행된다.
터미널에서(command prompt) ipconfig
를 입력하면 정보가 나온다.Default GateWay
의 ip주소를 localhost처럼 사용하면 된다.
단점: 느리닷!
]]>코드스피츠 강의 정리록
생소한 도메인으로 배우는게 좋다.
익숙한 도메인들은 익숙한 처리방법으로 처리하기때문에 객체지향을 배우기 어렵다.
때문에 80기는 게임을 통해서 진행할 예정.
객체지향 프로그래밍을 배우기 전,
프로시저 프로그래밍 형태의 코드를 알아본다.
아키텍트나 디자인패턴을 만드는 설계자들은
현상을 보고, 현상으로부터 프로그램 엔티티를 도출해서 설계를 들어간다.
블럭에는 타입이 있구나.
블럭 connect의 최저 갯수 제한이 있겠구나.
스테이지의 가로 세로 갯수
선택했던 블럭들을 돌아갈 수 있다.
새로운 블록이 떨어진다.
인지과학
가상세계임에도 불구하고 물리력가 중력을 기대한다 ㅋ
cf__1 게임이야기 ~모바일시대에서는 복잡한 core action이 많이 들어간 게임은 상품성이 없다. (안좋은 예: 와우)
core action이 단순한 게임이 상품성이 좋다. 최근 rpg게임들은 단순하게 변했다. 한붓그리기도 이미 오래전에 누가 찾아낸 코어액션중에 하나이다. 재밌는 반복거리를 찾아내면 벗어나려고 하지 않는다.
사람은 표면적인 것만 파악하려고 한다.
프로그램의 핵심은 데이터이다.
1 | column = 8; |
UML을 깊이 공부하면 5가지 종류의 여러가지 entity과 관계가 나온다.
싱글톤 객체
애플리케이션이 시작될 때 어떤 클래스가 최초 한번만 메모리를 할당하고(Static) 그 메모리에 인스턴스를 만들어 사용하는 디자인패턴.
생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나고
최초 생성 이후에 호출된 생성자는 최초에 생성한 객체를 반환한다.
싱글톤 패턴은 단 하나의 인스턴스를 생성해 사용하는 디자인 패턴이다.
1 | const Block = class { |
parseInt(Math.random()*5)
: 0 ~ 4 사이의 타입을 얻게됨Block.GET
)변화율을 평가하는 가장 쉬운 방법
변화율을 잘 디자인 했으면 책임이 없다고 생각됬던 객체는 수정되지 않아야한다.
우리의 목표는 보다 더 많은 파일을 안건드리고
일부파일만 건드려야한다.
객체지향할 때 클래스를 사용하는 경우 생성자를 봉인하자.
factory함수로 클래스를 얻어가게 하자.
static
키워드 써서 불러오게 해도됨.GET
)팩토리 함수 : 객체를 반환하는 함수
단일 책임원칙은 엄밀하게 지키려면 굉장히 어렵고,
섬세하게 바라보는 눈으로
언제나 의심해서 관리하지 않으면 실력..키워지지 않는다.
(빠르면 3년 늦으면 5년..ㅎ)
게임이라는 객체는 블록들을 소유하는 마스터 객체
클래스이냐? 싱글톤 객체이냐?
게임은 하나의 객체만 있으면 된다. (바둑판 하나.)
구지 클래스로 선언하지 않고, 싱글톤 객체로 만든다.
=> 싱글톤 객체
책임
2번과 3번은 내부에서만 알면된다.
외부에서 게임의 어떤 상태만 알면 될까?
1 | // 게임은 초기화된 게임이 바로 생성되어야 하므로, 즉시실행함수로. |
1 | const Game = (_ => { |
데이터를 소비해서
표를 다시 그려주는 로직.
1 | const Game = (_ => { |
배열을 루프돌아서
각각의 줄을 td를 갖는 tr로 바꿔서
table에 넣고 싶음.
배열의 고차함수를 쓰는 원리는 간단하다.
forEach
map
reduce
여러개의 집합을 하나의 스칼라값으로 바꾸는 것
1 |
|
move는 mousedown인 상태여야 의미가 있다.
down의 상태값 필요
현재 눌러진 블록의 위치값 알아야함.
event로부터 x,y값 전체좌표를 받아와서
x, y좌표를 이용해서 테이블 내에서 몇번째 블록인지, 데이터로 치환하게 된다.
현재 눌러진 블록이 첫 시작? 아니면 중간?
1 | const down = e => { |
1 | const column = 8, row = 8, blockSize = 80; |
getBlock이외의 밑에나오는 로직은 전부 인메모리 로직.
네이티브 레이어를 다루는 방법은 즉시 인메모리 객체로 변환한다.
좋은 개발자
말하면 코드로 옮기는 것이 리얼타임이 될때까지.. 훈련하자.
좋은 개발자는 제어문을 잘쓰거나, 코드를 한국어로 번역하거나 한국어를 코드로 번역하는 능력에 달려있다.
숙련을 많이 해서 실시간으로.
1 | // 네이티브 객체의 값을 => 인메모리 객체로 변환해주는 변환기 ! |
getBoundingClientRect
1 | DOMRect |
코어액션이 여기서 다 일어난다.
1 | const up = e => { |
선택항목이 2이하면 모두 초기화시킨다.
1 | const up = _ => selected.length > 2 ? remove() : reset(); |
쉬운 것은 의존성이 없다. 고칠 일이 적다.
복잡한 것부터 짜면 의존성이 많은 것부터 짜게 되고,
나중에 깨달은게 많을수록 더 많이 고치게 된다.
1 | const remove = () => { |
forEach는 for문보다 대화가됨.
column을 돌면서 row를 계산해서 떨어뜨리는 일을 한다.
한턴에는 한칸씩 떨어진다.
중력에 의해 떨어지는 방향은
column기준이기때문에 column을 먼저 loop돌린다.
row는 맨 아랫줄부터 떨어지는 작업을 해야하므로.. (전체row -1) 부터 시작
1 | const drop = _ => { |
ㅋㅋㅋ ㅠㅠ 대댜냐댜..
머리가 좋아지는수밖에 없다.
잘짜고, 쉽게 짤때까지 머리로 훈련하는 수밖에 없다.
알고리즘, 코딩인터뷰, 자료구조, 트리구조 보다 도메인 해석 능력을 키우자.
어떠한 도메인에 대해서 알고리즘을 짜는 능력은 훈련밖에 없다.
복잡한 일이 일어나는 것을 눈으로 관찰해서 어떤 일인지 파악한 다음에
코드로 차근차근 푸는건 훈련밖에 없다.
이거 안되면 아키텍처고 디자인패턴이고 필요없다..
채울준비를 하는 것은 밖에부터 채워야하는 애들이 예쁘게 내려오게 하기 위해서.
1 | const fills = []; |
누른상태에서 다음(혹은 이전) 블럭으로 움직이는 상태
1 | const move = e => { |
1 | const move = ({ pageX: x, pageY: y }) => { |
1 | // 받아오는 curr 블럭과 cache해놓은 curr 블럭을 비교하여 인접해있는지 검사. |
자바스크립트에서 배열의 고차함수로 여러 제어문을 제거할 수 있다.
프로시저 함수: 반환값이 없는 함수
sideEffect가 엄청 많다.
현재 로직들은 모두 프로시저 함수.
앞으로 객체지향으로 리팩토링 예정.
1 | // Game에서 사용한 interface |
1 | // 도저히 머리가 따라가기 힘들어서 TS로 우선 변환.. |
코드스피츠 강의 정리록
생소한 도메인으로 배우는게 좋다.
익숙한 도메인들은 익숙한 처리방법으로 처리하기때문에 객체지향을 배우기 어렵다.
때문에 80기는 게임을 통해서 진행할 예정.
객체지향의 반대말은 값지향이다.
객체지향과 값지향을 비교해보면서 기본개념을 잡고 넘어가자.
객체지향에서는
함수의 인자를 보내던,
변수에 대입을 하던,
연산을 하던
참조를 사용한다.
그렇다고 오브젝트는 값이 아닐 것이다 라고 생각하면 안된돠.
오브젝트도 값으로 생각하는 언어들이 있다.
언어마다 어떠한 타입에 대해서 직접적으로 값으로 처리할지
참조로 처리할지 결정하는 것이다. 원래 값이고 원래 참조다 라는 개념은 없다.
참조는 순식간에 전파된다.
객체 컨텍스트에서는 참조를 쓴다고 했다.
참조가 되면 원본은 힙메모리
에 만들어지고
모든 객체는 힙메모리의 주소만 참조하고 다니는 것이다. 주소값만 복사되고 있는 것.
⇒ 한번 만들어진 객체는 통제권을 쉽게 벗어나서 주소의 복사가 왕창 일어난다는 것이다.
객체지향의 큰 어려움은 객체를 일단 만들고 나면
주소값을 보호할 수 있을 것 같지만 실제로는 순식간에 퍼져나간다.
⇒ 문제는 그 주소값을 참조하는 변수에 새로운 객체를 할당할 수 있다.
A라는 변수가 원래는 old 객체를 참조하고 있었는데,
A라는 변수에 new객체를 할당하면 새로운 주소가 A변수에 들어간다.
⇒ A는 아무 문제가 없지만, B = A, C = B의 B,C변수들이 다 바보가 된다.
즉, A의 참조부분을 잡았던 애들이 다 바보가 된다.
B와 C는 old를 가리키고 있지만, A는 이제 new가 되었다..
객체지향에서는 객체 참조키를 함부로 노출하지 않고 쥐고 있지 않으면
순식간에 오염이 전파되서 A객체도 new객체를 받아들일 수 없다. 겁나니까.
객체지향은 이러한 단점이 있다. 참조가 쉽게 전파된다.
참조 전파를 막는 장치가 있거나,
섬세하게 관리하지않으면 참조가 순식간에 전파되어서
참조를 전파시킨 본인조차도 새 객체를 받아들일 수 없다. 그럼.. 전체가 썪어서 망가진다..
그에 비해서 값지향은 매번 복사가된다. 전파되지 않는다는 것이다.
끊임없는 클론이 양산된다.
⇒ 메모리가 엄청나게 많이 사용된다.
⇒ GC에 의존할 수밖에 없다.
값으로 계속 복사가 되기때문에
값에 대한 컨텍스트를 이어갈 수 없고
컨텍스트를 포함한 새로운 값을 만드는데 성공해야한다.
값지향에서는 히스토리를 볼 수 없고 상태의 흐름을 볼 수 없다.
중간중간에 흔적을 따로따로 상태를 보관해줘야한다.
결과물이 복잡할수록 함수의 복잡성은 올라간다.
⇒ 수정은 더욱더 올라간다.
ex) 함수형, rx
객체지향은 싱글톤 객체나 메모리상의 유일한 객체를 참조로 전파시키고 있으니까,
메모리상의 유리한 점이나 객체의 생성에 대한 안정성을 확보해 줄 수 있다.
다만, 주소의 전파가 일어나면 썩어들어간다.
본인의 상태를 본인이 책임질 수 있다.
class 내에 메소드들이 this가 안나오면 메소드가 아니다.
this
가 없고, 인지와 지역변수만 쓰는 것은 유틸리티 함수이다.리팩토링할 때 알 수 있는 것은
우리가 짠 클래스에 this를 사용하지 않는 메소드가 나온다는 점으로부터,
값 컨텍스트
를 섞어서 문제를 풀었다는 것을 알 수 있다.리팩토링이 끝나고 나면, this만 사용하는 클래스의 협력으로 문제가 풀리게 된다.
그것이 우리의 궁극적인 목표이기도 하다.
우리가 알파고가 아니다. 이세돌이다.
사람의 한계로 인해서 한번에 하나밖에 안된다.
인간의 한계때문에 SOLID원칙이 있는 것이다.
⇒ 그래서 컨벤션이 존재.
왜 안보여 줄까? ⇒ 지식 (knowledge)
은닉을 하는 이유는 사람때문이다. 사람을 못믿기 때문에..
객체지향은 사람 중심의 사고로 사람을 무지하다고 생각하는..ㅋㅋ 패러다임이다.
은닉과 전혀 다른 이야기이다. 나의 행동을 구체적으로 부여주지 않으려고 하는건 아니다.
추상화된 수준으로 설명하고 싶은 것.
(ex_ATM기기: 돈세는 소리로 사용자의 목적을 인지시키지만, 실제 내부에서는 많은 일이 벌어진다.)
캡슐화를 common sense로 제공한다.
*가장 설계능력이 많이 필요한 부부은 캡슐화이다. *
좋은 아키텍쳐는 캡슐화를 잘한다.
캡슐화를 하는 이유 중 하나는 객체망을 숨기기 위한 것도 있다.
아키텍쳐들이 하는 일들이다.
기계 친화적인 코드는 없다. 기계친화적인 포맷은 없다.
사람에게 이해가 쉬운 코드. 사람이 잘 사용할 수 있는 캡슐화.
⇒ 객체지향이 지원하는 것이다.
값이라는 것은 어떻게 구분할까?
객체 간의 식별은 메모리의 주소로 한다.
값에서는 메모리의 주소는 틀리지만,
타입에서 인정한 동과평과방법에 의해서
값의 동과를 판별하는 전용식이 따로 있다.
메모리의 주소로 평가하는 것이 아니라
값에 따라서 평가하는 방법이 다 다르다.
값에서는 값을 평가하는 기준이 따로 있고,
그것으로 동과를 평가한다. (메모리의 주소로 평가하지 않는다.)
값이 있으면 값의 동과를 평가하는 식은 값 밖에 있다.
메소드도 아니다.
메소드로 처리하지 않고 값을 처리하는 유틸리티 함수로 값을 처리하게 된다.
메모리에 있는 값 그 자체를 사용한다.
cf__2. 객체도 값처럼 사용하면 값 컨텍스트로 넘어간다.
자바같은 언어에서 객체는 생성할때 무조건 고유한 해시코드를 갖고 태어난다.
객체는 원래 메모리 주소로 구분해야하는데, 해시코드를 어딘가에 캐시잡아놓고, 해시코드와 해시코드를 비교해서 객체의 동과를 비교하려고 한다. 이런 경우 객체지만 값 컨택스트로 넘어간다.
메모리의 주소로 비교해야하는데, 특별한 값의 비교방법으로 동과를 평가하면 그 비교식들은 순식간의 값 컨텍스트로 바뀐다.
값 지향에서는 값과 독립적인 함수일가?
인티저를 더하는 함수는 값에 독립적일까? 독립적이다.
단지 타입에 종속되어있다.
어떤 함수는 인티저 타입만 건드릴 수 있고,
어떤 함수는 더블 타입만 건드릴 수 있다.
이때 말한 타입은 객체타입이 아님.
타입에 따라서 값타입이냐
객체타입이냐는 굉장히 큰 구분점을 갖게 된다.
값타입에서는 그 타입이 함수를 그룹짓는 기준이 되어버린다.
값에서는 하나하나 값을 구분하는 것이 아니라
값의 타입만 구분할 수 있기 때문이다.
그 다음에는 이 값과 값의 크기만 갖는것이다.
객체는 그렇게 구분되지 않는다.
메모리만 있으면 독립성이 확보이다.
값은 복잡한 녀석들이다 의외로
값은 계속 복사되고, 계속 역할이 없는 상태로 존재하기 때문에
값지향을 이용해서 문제를 처리하기 위해서는
값을 처리하는 함수의 조합으로 문제를 처리하는 수밖에 없다.
HOC
끊임없이 그 함수가 값을 만들거나 값을 받아들이면서
최종적으로 도메인을 해결하기 때문에
결국에 값을 통한 문제들은 대부분 파이프라인으로 결론을 내게된다.
ex__도자기 공정
도자기를 예로 들자.
도자기를 만드는 방법을
흙을 반죽하고 ⇒ 반죽한 흙을 빚어서 도자기를 만드는 과정이라고 치면.
과정을 유틸리티 함수로 만들어보자.
함수는 흙을 받고, 반죽을 return하게끔 만들 수 있다.
이런 함수는 고정상태와 고정출력이 있다.
어떤 과정을 순수하게 고정상태와 고정출력이 있는 상태로 구분지어서 나눌 수 있냐가 중요하다.
-값지향을 하기 위해서는 상태를 구분지을 수 있냐 없냐 즉,
내가 처리하려는 공정을 딱딱 잘라낼 수 있는지 없는지가 굉장히 중요하다.
하지만 우리 비즈니스의 요건들은 딱딱 잘라낼 수 있는 상황이 아니다.
무조건 아닌 것은 아니고, 우리가 속해있는 도메인에 달려있다.
값지향으로는 가역성을 만들기 어려워서 리셋을 한다.
값과
immutable과
rx와
함수형으로 풀 수 있는 문제는
그렇게 많지 않다.
주요 도메인은 객체지향을 쓰는 이유는 사람의 마음은 기계가 아니기 때문에..
개발 잘 하고싶으면 인지과학, 인지심리, 뇌과학 배우면 좋다.
사람들이 좋아하는 것을 하면 좋은 아키텍처가 될수있다 .. :)
객체의 책임을 도출하고 객체망을 구성하는 것
책임 (or 역할)을 도출하는 기준으로 사용할 수 있는 후보군
3가지 요령이 있다. (3번으로 갈수록 뒤로갈수록 중요성이 높다.)
객체디자인을 할 때 도메인에서 뽑는 것이 좋다.
DDD 개발: 의존성때문에!
개발은 크게 2가지 영역을 다룬다고 생각해도된다.
I/O를 사용하면 드득거린다.
쿠키를 읽을때 드득거리는 것을 볼 수 있다.
때문에 일부러 웹워커
같은 것을 사용한다.
인메모리 영역과 네이티브 영역을 분리해서 객체를 구성해라.
믹스한 경우
이 두개를 분리한 사례
도메인보다 더 중요하다.
네이티브 도메인을 분리해주자.
네이티브 영역을 분리해서 프로그램을 구축하지 않으면
새로운 네이티브 영역과 바인딩하거나 환경이 바뀔때 비용을 든다..
네이티브 영역에 의존하면 안된다.
의존하지 않기 위해서는 인메모리, I/O 따로 만들어야한다.
도메인 패턴
도메인 패턴을 따르지 않는 패턴을
enterprise pattern에서 transaction script pattern
변화율의 기준으로 나누어야한다.
예를 들어
고객의 비즈니스 요구사항이 바뀔때 바뀌는 부분이고
고객의 시장반응이 바뀔때 바뀌는 부분이라면
해당 변화율 기준으로 나눠놔야한다.
구간을 나눠서, 책임을 나눌 때
어떠한 일때문에 바뀌는지에 따라서 나눠 놓으라는 것.
모든 프로그램은 변하니까.
변하는 이유에 따라서 나눠놔라.
좋은 아키텍트가 되는 중요한 자질이다.
변화율을 꽤뚫어봐라!변화율에 대한 센스가 아키텍트의 중요한 자질.
도메인을 기준으로 책임을 도출해보자.
네이티브 영역을 분리해서 책임을 도출해보자.
변화율을 인식해서 책임을 도출해보자.
ECMAScript6 책 (두고두고 보는 자바스크립트 표준 레퍼런스)
정리중 입니다.
스펙에서 @@iterator
형태로 작성된 것을 볼 수 있는데, @@
는 Symbol
대신 사용한 것이다.
Well-Known Symbol은 스펙에서 처리 알고리즘을 구분하기 위해 부여한 이름이다.
자바스크립트 프로그램에 같은 이름의 Well-Known Symbol을 작성하면 엔진의 디폴트처리를 실행하지 않고, 프로그램에 작성된 코드를 실행한다.
11개의 Well-Known Symbol이 있다.
[object Object]
형태에서 Object를 Symbol.toStringTag 값으료 정하면 Object 문자열이 해당 값으로 출력된다.
[obejct Object]
로 출력되므로 이를 구분하기 위해 Symbol.toSTringTag
로 구분지으면 된다.1 | b.prototype[Symbol.toStringTag] |
1 | var a = {} |
1 | class a {}; |
개발자 코드로 Well-Known Symbol 기능을 대체할 수 있다.
Symbol.iterator()는 이터레이터 오브젝트를 생성하며 반환한다.
Symbol.iterator는 String, Array, Map, Set, TypedArray 오브젝트의 prototype에 연결되어 있다.
오브젝트의 [Symbol.iterator]를 호출하면 이터레이터 오브젝트를 생성하여 반환한다.
배열을 처리하기 위한 이터레이터 오브젝트를 생성하여 반환한다.
배열 엘리먼트를 하나씩 처리할 수 있다.
1 | let numberArray = [10,20]; |
for..of
문에서 배열이 반복되는 것은 numberArray 오브젝트에 Symbol.iterator
가 있기 때문이다.numberArray[Symbol.iterator]();
Array.prototype[Symbol.iterator]
와 같은 원리
Object에는 Symbol.iterator가 없다. 때문에 for-of를 사용할 수 없다.
obj 내에 Symbol.iterator를 작성하면 반복 처리할 수 있다.
Symbol에 대해서 이해가 안갔는데 C언어의 enum과 비슷한 개념이라고 설명한 부분에서 살짝 감이 왔다.
ECMAScript6 책 (두고두고 보는 자바스크립트 표준 레퍼런스)
인프런 JavaScript ES6+ 제대로 알아보기 – 중급 :: symbol
심볼은 3가지 형태로 사용할 수 있다.
string, number, boolean은 레퍼(Wrapper) 오브젝트가 있다.
wrapper 오브젝트는 vlaueOf()로 프리미티브 값을 구할 수 있지만, symbol은 값을 반환하지 않는다.
Symbol([description])
1 | let sym = Symbol(); |
''
, Array의 []
처럼 Symbol을 생성하는 리터럴이 없다.Symbol()
형태를 반환한다.
이는 symbol의 특징이다.undefined
로 인식한다.1 | feature1: const sym = Symbol(); |
Object(123)처럼 Object()의 파라미터에 123을 지정하면 Number 오브젝트를 반환한다.
유일한 값을 갖는 Symbol 특성을 활용하여
Symbol 값을 오브젝트의 프로퍼티 키로 사용하면 프로퍼티
키가 중복되지 않습니다.
[Symbol()]
형태와 같이 대괄호 안에 Symbol()을 작성
1 | {[Symbol()]: 123} |
이렇게 프로퍼티 키에 작성한 Symbol()을 symbol-keyed property
라고 한다.
{ ABC: 123 }
에서 ABC
에 Symbol값을 넣은 것이다.1 | let sym = Symbol("123"); |
대괄호를 사용하지 않고 obj.sym
형태로 작성하면 에러는 안나지만 undefined
가 반환된다.
<<>>
형태로 표기하고 있다.for-in 문에서 symbol-keyed property는 열거되지 않는다.
[[Enumerable]]: false
이기 때문.[[Enumerable]]
은 기본적으로 true이다.)1 | let obj = {nine: 999}; |
일반적으로 for-in문으로 객체를 순회하면서 symbol-keyd property는 접근할 수 없다.
때문에 객체의 고유한 식별자로써, 상수개념으로 사용한다.
외부 스코프에서 의미가 있지 않는 값들만 symbol화 시킨다.
은닉화의 목적이 있기때문에 외부 스코프에서는 접근가능하지 않아야하지만 내부에서는 가능하도록 만들어야한다.
Object.getOwnPropertySymbols()
를 사용하여 symbol-keyed property 키값들을 열거할 수 있다.Reflect.ownKeys
를 사용하면 symbol-keyed property 키와 값까지 알 수 있다.1 | const symbolOne = Symbol("symbol one"); |
1 | let sym = Symbol("key"); |
빈 오브젝트가 반환된다.
이는 Symbol 값을 외부에 노출되지 않도록 하기 위한 조치이다.
1 | const x = () => { |
Symbol.for
public member 전역공간에서 공유되는 심볼.
여기저기서 많이 사용되는 공용상수를 사용할때 사용
1 | const a = Symbol.for('abc') |
?!a와 b가 값과 타입이 같다고 나온다.Symbol.for
는 for의 인자를 식별자로 사용한다.
1 | const obj1 = (() => { |
복습할때나 이 문제가 까먹었을 즈음에 풀어보기
???
구해보기1 | { |
코드스피츠 강의 정리록입니다.
단순한 배열 루프인 경우 간단히 이터레이션을 작성할 수 있다.
1 | { |
es6와 es6이전의 객체 리터럴의 큰 차이점이 무엇인가
1 | { |
루프를 잘 짜고
보다 어려운 로직을 짜는 방법은
내 머리가 선언한 변수만큼을 추적할 수 있어야 한다…
기본적인 알고리즘 전략은 최대한 상태를 덜쓰는것. 내 머리가 추적할 정도로..
각각이 컨테이너 형이라면
그 컨테이너를 다시 해체해서 다시 배열에 붙여준다.
더 이상 컨테이너 형이 아닐 때까지
1 | // 프로토콜만 맞춰주면 된다. |
for(var k in v)
for…in문은 prototype의 key까지 다 나오기 때문에 hasOwnProperty
를 조건에 추가해야한다.
1 | for(var k in v){ |
현재 상태에서는 순서 보장이 안된다.
1 | let x = []; |
값인 타입을 v instanceof Object
로 판단할 수 있다!
1 | { |
자바스크립트 언어는 2가지로 되어있다.
코어객체에 있는 메서드들을 사용하는 것이
기본 언어자체의 문법을 사용하는 것보다 더 안전하다.
ex. for..in보다 Object.values
재사용성 올리기
unshift
나shift
로 인해서 data의 배열이 빈배열이 되는 상황이 된다.
클래스로 묶어서 매번 부를때마다 인스턴스를 반환하는 형태로 만들자.
함수를 정의할때 3가지 스타일
함수는 값이기 때문에 변수에 할당하는 형식이 맞다. 더 정확하게 호이스팅에 의존하지 않고 어느 시점에 함수를 만들었다를 명확하게 코드로 인지할 수 있기 때문에 function으로 시작하는 함수 정의방법은 아예 금지시키고 못쓰게 하는 경우가 많다. lint에도 함수선언문 금지룰이 있다.
클래스도 하나의 값이다. 변수에 할당이 된다. 변수의 할당 없이 class..로 시작하는 선언방법은 이 클래스가 언제 만들어졌는지 모호하게 만드는 관점이 있다.
1 | const Compx = class { |
shift를 사용하는 것은 data가 배열이 와야하는 조건이 있기 때문에
data의 사본을 만들때 아예 배열화시킨다.const data = [JSON.parse(JSON.stringify(this.data));]
if절을 보면 mandatory가 아닌 optional.
1 | const Compx = class { |
위의 루프는 목적이 있는 루프이다.
목적이 있는 루프를 만들고 목적을 바꾸면 루프를 다시 짜야한다.
1 | (data, f) => { |
이 상황에서 f(v)를 호출하는 body에 본래 목적과 다른 로직이 추가 될 경우,
같은 로직을 복사하고 원하는 로직을 추가해야하는 상황이 발생한다.
문으로 로직을 작성할 때는 별다른 방법이 없다.
=> 제어문을 재활용할 수 없으므로 중복정의할 수 밖에 없다.
=> 문은 사용하고 나면 재활용할 수 없는데 이걸 어떻게 객체화하지?
구조를 추상화해보자.
우리가 배우는 거의 모든 priority 기법은 if를 어떻게하면 제거할까에 대한 연구일 수도 있다. 사람은 if가 많아지면 감당이 안된다. 조건이 많아져서..
if를 어떻게하면 제거할 수 있을까?
아래는 if가 3개이다.
1 | (data, f) => { |
1 | // 😵😵😵 |
자바스크립트에서도 일반명사처럼 생긴 고유명사가 많이 나오고, 그중에 하나가 interface. 자바에서의 interface는 따로 있지만, 자바스크립트에서의 interface는 무슨 의미인지, 뭐에 쓰는 용어인지 알아보자.
자바스크립트 스펙에 정의되어있는 interface 규격에 맞춰 자바스크립트의 루프가 구현되어있기 때문에 중요하며, loop를 배우기 전에 알아보자.
ECMAScript 공식문서에서는 interface에 대한 정의를 명확하게 내리고 있다.
1 | { |
cf__1. es6 객체리터럴
test옆에 바로 괄호?
:
을 생략하고 바로 괄호를 쓸 수 있는 문법이 추가되었다.1 | { |
자바스크립트 엔진 레벨에서 여러가지 interface를 정의하고 있다.
IteratorResultObject
를 반환하는 함수가 온다.value
와 done
이라는 키를 갖고 있다.done
은 계속 반복할 수 있을지 없을지에 따라 불린값을 반환한다.true
일때는 value는 undefined
라는것도 정의되어있음위 조건만 만족하면 Iterator 객체로 본다.
아래는 타입스크립트에서 자바스크립트 내장 객체들을 정의해놓은 type definition 파일의 일부를 가져왔다.
1 | // lib.es2015.iterable.d.ts |
1 | { |
이터레이터 프로토콜(: 데이터 컬렉션을 순회하기 위한 프로토콜(미리약속된 규칙))은 next메소드를 호출하면 iterable을 순회하며 value, done 프로퍼티를 갖는 iteratorResultObject를 반환한다.
1 | { |
Iterator Object
를 반환하는 함수가 온다.1 | // lib.es2015.iterable.d.ts |
1 | { |
iterable은 Symbol.iterator 메소드를 구현하거나, 프로토타입 체인에 의해 상속한 객체를 말한다.
Symbol.iterator 메소드는 이터레이터를 반환한다.
- ES6 추가된 새로운 primitive type
- 객체가 아닌 값으로 인식된다는 말.
- typeof로 보면 Symbole 타입이 나온다.
- primitive이지만 객체의 키로 사용할 수 있는 특징이 있다.
- Symbol.iterator는 이터레이터 오브젝트를 생성하면서 반환한다.
- 오브젝트의
[Symbol.iterator]
를 호출하면 이터레이터 오브젝트를 생성하여 반환한다.
- 심볼은 주로 이름의 충돌 위험이 없는 유일한 객체의 프로퍼티 키(property key)를 만들기 위해 사용한다.
iterator만 있으면 되지 않을까? 왜 iterable이 필요하지?
왜 for, while, do..while을 쓰지 않게 하고 이런걸 제공할까
식
으로 바꾸고 싶다는 마음이 생김!!현대언어의 기본적인 패러다임은
문을 제거하고 전부 식(값)으로 바꾸버리는 것.
모든 문을 함수에 집어 넣어버리면
함수에서는 값이 반환되는 형태이고, 그 함수를 호출하면 문을 원하는 시점에 실행할 수 있게된다.
for문이나 while문을 값으로 바꾸고 싶다.
반복 전용에 해당되는 객체로 바꿔주면 된다.
while
1 | let arr = [1,2,3,4]; |
iterator
1 | { |
즉, 반복행위와 반복을 위한 준비를 분리
3. 반복을 재현할 수 있음
반복 자체를 하지 않지만,
외부에서 iterator를 이용해서 반복하려고 하는 상황을 위해서,
반복에 필요한 조건과 실행을 미리 준비해둔 객체를 갖고 있는 것이다. (iteratorResult객체)
next만 부르면, 몇번이고 반복할 수 있다.
이제는 더이상 복잡한 loop의 상태조건이나 문의 실행을 다 빼버리고,
외부에서는 반복이라는 행위만 하면된다.
=> 반복기와 반복조건을 분리
직접 Iterator 반복처리기를 구현해보자. 커스텀
1 | // 1. 반복기 |
반복되야되는 조건에 해당되는 값들과
반복기를 분리했더니
반복기쪽에서는 그냥 돌리기만 하면되는 책임으로 확 줄고 (loop함수),
나머지 상태관리나 루프에 대한 모든 책임은 다 iterator객체가 가져갔다.
개발자스스로 나름대로의 구조와 이름으로 짤수도 있다.
단지 이제는 자바스크립트 표준이 있다.
이터레이터 패턴을 구현하는데에 있어서 자바스크립트 표준 스펙이 나왔고, 이걸 구현하는 공식적인 방법이 스펙으로 정의되어있다.
만약 스스로 나름대로의 이터레이터를 구현해 왔다면, 이제는 자바스크립트 표준 인터페이스에 맞춰서 iterator를 구현하시는 쪽으로 바꿔야한다.
언어의 혜택이 많기 때문
언어의 지원을 받는다는 것은 무슨뜻일가.
언어가 iterator 인터페이스에 대해서 처리해주는 내장 기능이 있다.
우리가 만든 모든 객체가 iterator 인터페이스를 충족해주면, 언어가 제공하는 문법적인 요소를 다 사용할 수 있다.
iterable객체가 아닌데 아래의 처리기들을 사용하면 스크립트가 죽는다.
어떤 객체가 Iterable이라면, 그 객체에 대해서 자바스크립트에서는 아래의 기능들을 사용할 수 있다.
Array destructuring 배열해체
1 | // iter는 iterable 객체. |
=
의 왼쪽에 오면 변수이름이 된다.Spread 펼치기
1 | const iter = { |
Rest Parameter (나머지 인자)
1 | const iter = { |
for ...of
while, for처럼 권한이 있지않고 권한이 전혀 없는 for.
1 | const iter = { |
for...of
iterator에서 value만 받아서 내려준다.배열이나 object를 써야지 이 혜택을 받는 것이 아니라, iterator만 만들면 이 혜택을 받을 수 있다.
객체 만들때는 괴로울지 몰라도, 사용할때는 예쁘게 작업 가능.
신규로 출시되는 많은 API가 iterable을 포함하고 태어나기때문에
iterable interface는 es6세계에서 반드시 이해하고 외우고 있어야 하는 내용이다.
자바스크립트 es6이후에는 반복을 위해서 iterable을 만든다.
제곱을 요소로 갖는 가상컬렉션 😵😵😵
1 | const N2 = class { |
하나의 Object는 여러 개의 인터페이스를 충족시킬 수 있다.
이 객체는 Iterator객체임과 동시에 iteratorResultObject이기도 하다.
함수형 패러다임에서는 instance를 new 연산자로 생성하는 대신에,
함수를 생성함으로써 그때에 있는 자유변수를 instance의 field처럼 쓰게 된다.
자바스크립트에서는 instance를 만들면서 field지정할것인지.
함수를 생성하면서 자유변수를 지정할 것인지 선택할 수 있다.
혹은 섞어 쓰거나.
- 이게 자바스크립트가 혼란스러운 이유…
- 비단 자바스크립트만 그렇진 않다..
함수는 함수가 만들어지는 시점에 바깥쪽에 있는 변수들을 캡쳐해서 마치 지역변수로 쓸 수 있는 권한이 있다.
자유변수가 잡혀서 사용되는 닫혀진 공간을 클로저라고 한다.
함수는 곧 클로저라고 할 수 있다. 자유변수를 가둬둘 수 있기 때문에
자료구조를 iterable로 구축하는 훈련이 되있어야하지만, 문법적인 혜택을 누릴 수 있다.
하지만 생각보다 iterable 객체를 만드는 것이 리소스가 많이 든다.
generator함수로 해결할 수 있다.
function*()
generator 함수를 생성하는 리터럴.
1 | const generator = function*(max){ |
yield라는 키워드
참고자료
https://helloworldjavascript.net/pages/260-iteration.html
https://poiemaweb.com/es6-iteration-for-of
https://jusungpark.tistory.com/25
optional flow control에서는 if문
에 대해서 다룬다. if문에서 가장 중요한 것은 모든 상황에 대한 예외처리이며, 특히 if..else을 사용할 경우 else문 뒤에는 mandatory 상태의 문이 와야한다. 후방결합이라는 특징때문에 else if 사용을 조심해야한다. 병행조건일때는 switch문을 쓰고 부분집합에서의 조건문이 필요할 경우에는 if..else를 사용한다.
if문의 여러 중첩을 else if문으로 쓰곤했는데, 많은 상황을 예외처리 한것인가에 대해 항상 의문이 들곤했었다. 이번 시간을 통해서 else if문은 지양하기로 하고, else문 뒤에 조건문을 추가하고 싶을 경우 중괄호 이후에 if else문을 써서, else뒤에는 mandatory한 상황을 만들게끔 습관을 들이기로 했다.
Iterate Flow Control에서는 For문
과 While, do..while
문을 다룬다. For문은 3가지 식을 넣을 수 있는데 첫번째는 식과 문 중에는 선언문만 올 수 있고, 두번째는 boolean을 반환하는 조건식이 오며, 빈값일 경우 무조건 truthy라는 특징이 있으므로 무한루프에 빠지지 않게 조심해야한다. 세번째는 식이 오는데, statement의 마지막에 처리되므로 statement 마지막에 두어도된다. while문은 조건식이 필수이며, 조건식과 관련된 코드가 body에 안나올 경우 무한루프에 빠지게된다. do..while문은 while 조건문 뒤에 ;
을 붙여야한다.
코드스피츠 강의 정리록
77 동영상 음원문제로 77교안을 토대로 73강의를 들으며 작성
if (condition) statement1[else statement2]
1 | if (c > 5) { |
1 | if (c > 5) { |
0, false, null, undefined,"", NaN
이 있다.특정 상황에 따라 optional한지 mandatoy한지 다르다.
1 | if (expression) //optional |
암묵적인 오류(context error)
예1)
1 | if (a) // mandatory |
위의 코든에서 첫번째 else뒤에는 mandatory되어야하지만, optional하다.
b && a
의 값이 다르기 때문 1 | if (a) |
에2)
1 | if(c === 1){ |
else 다음에 옵셔널한 if만 놓여있다.
else 안에는 mandatory해야한다.
1 | if(c === 1){ |
arrow function
과 if else 구문만 오른쪽에서 왼쪽으로 후방 결합
한다.대부분의 버그는 후방 결합에서 일어난다.
1 | if (c===1){ |
병렬조건을 선택할 때 절대로 else if
를 쓰면 안되는 이유이다.
else if
는 원래부터 위험한 코드고,이렇게 if else를 봤더니..
부분집합
에서만 쓰인다.부분집합을 다시 분기할때
..switch를 쓴다.
내가 평가해야할 식들이 동등할 경우 !!! switch문으로 간다.
내가 평가해야할 식이 nested되어야 할 경우 if중첩.
병행조건에는 반드시 예외가 생길 수 있는 가능성이 있기 때문에
switch에는 default가 필수이다!!
mandatory로 시작했으면 mandatory로 끝내야하고
optional로 시작했으면 optional로 끝내야하고
optional과 mandatory를 섞어 써야한다면
자기 코드의 의도를 명확하게 해서 변화가 일어날 때 어디까지만 수정하고 나머지는 여파가 없게끔 하는 방법에 대해서 익힐 필요가 있다.
코드를 짤때 어떻게 섬세하게 짤 것인가.
반복문
for문의 3개의 선택식에 어떤 코드를 넣어야할지 반드시 이해해야한다.
for ([initialization]; [condition]; [final-expression])
InitializationLimited Statement
선언문 또는 식이 올 수 있다.
혹은 공문도 올 수 있다.
식 또는 변수 선언. 주로 카운터 변수를 초기화할 때 사용한다.
condition (:조건)
매 반복마다 평가할 식.
평가 결과가 참이라면 statement를 실행한다.
이 식을 넣지 않을 때(공문) 결과는 언제나 참이다. (Empty Truthy
)
결과가 거짓이라면 for문의 바로 다음 식으로 건너 뛴다.
final-expression
매 반복 후 평가할 식.
다음번 condition 평가 이전에 발생한다.
statement 끝에 있는것과 같는 상황이다.
즉, statement 마지막에 실행된다. (Last Execution
)반복해서 쓰지 않기 위해서 3번째 항목에 넣는것.
1 | var a = 3; // declare statement. 문이다. |
while (condition) statement
1 | while(truthy){ |
do statementwhile (condition);
;
붙이는게 공식문서에 명시되어있는 규칙;
붙이면 됨do a++; while(a);
while문과 do..while문은 평가식에 관여되어있는
상태값을 바꾸지 않으면 무한루프에 빠질 위험이 높다.
식별자와 관련된 코드가 안나온다면 무한루프
1 | var a = -1; |
현실코드
1 | while(act.method().c){ |
??? 뭔지 모름.
이런 코드는 무조건 배재해야한다..
1 | var a = act.method().c |
적어도 body안에 조건식에 나오는 상태가 되었다..
참고자료
https://mkki.github.io/code-spitz/2018/07/12/code-spitz-2.html
코드스피츠 강의 정리록
Flow란?
우리가 짠 파일이메모리에 적재되고,
적재된 순간, 명령과 데이터로 나눠져서 적재된 다음에
명령이 쭉 한꺼번에 실행되는데,
명령이 차근차근 실행되는 과정.
자바스크립트 언어의 기본적인 문처리 기법을 알아보자.
자바스크립트는 문을 처리할때 식과 다르게 처리한다.
식은 하나의 값으로 처리될 뿐이지만,
문은 실행단위로 처리된다.
문을 10개 쓰면, 10개의 실행단위가 생각난다.
(식은 10개 써도, 값 하나로 수렴될 뿐이다.)
문의 갯수를 늘리면, 자바스크립트 엔진은 갯수만큼을 처리해야할 과제로 알고 있다.
한줄한줄의 문이 생길때 마다 과제로 등록해 놓는다.
=> Record
우리가 일반적으로 문을 짜면 Record 하나하나로 번역이 된다.
자바스크립트 엔진은 우리가 짠 코드를 파싱할때 문들을 Record단위로 파싱한다.
Record가 하나하나 생성이되면 flow를 타고 쭉 움직인다.
Record를 만들고
Record를 실행하는 과정이
자바스크립트 엔진의 주 작동원리이다.
요즘 현대 브라우저들은 자바스크립트 3.1엔진에서 돌지 않는다.
(인사이드 자바스크립트나 자바스크립트를 말하다와 같은 책들은 좋지만, 작동원리는 현대 브라우저와 다르다. (3.1버전 엔진기준으로 설명된 책))
모든 항목에 있어서 브라우저들이 해석하는 방식이 달라졌다. 스펙문서도 달라짐.
자바스크립트 엔진의 작동원리를 지금 버전에서 배워도, 매년 스펙이 갱신되기 때문에 내가 알고 있던 지식이 다음해에는 무의미해질 수 있다.
기저층의 작동원리보다는
무엇을 의미하고 추상적인 의미는 무엇인지 체계를 배우는 것이 더 의미있다..
= 작동원리보다는 근본적인 부분을 배우자.
if문이라서 분기를 할 수 있다던지, loop구분이라서 계속 flow를 돌릴 수 있는
flow 제어를 하면 레코드를 선택하거나 레코드를 순환시킬 수 있는 권한을 갖게 된다.
flow 제어를 할 수 있는 문을 record로 바꿀때는
Completion record로 바뀐다.
completion record은 record를 뭘 선택할 수 있는지 flow에 관여할 수 있다.
자바스크립트 엔진은 우리가 작성한 문을
Record와 Completion record로 나누고,
Completion record들이 어떤 레코드를 선택할지 결정하는데 사용한다.
직접 flow control하는 명령어를 배워보자.
자바스크립트에서 사용할 수 있는 직접 flow control에는 label이 있다.
자바스크립트 변수 identifier
A JavaScript identifier must start with
a letter, underscore (_), or dollar sign ($);
subsequent characters can also be digits (0-9). Because JavaScript is case sensitive, letters include the characters “A” through “Z” (uppercase) and the characters “a” through “z” (lowercase). (참고)
:
를 붙여주는 순간 label이 된다.Label의 scope?
1 | <script> |
Uncaught SyntaxError: Illegal break statement
1 | <script> |
start
test
break
는 사용할 수 있다.label 영역이 아닌곳도 될까?
label 영역이 아는곳에서 되게 하려면 label 영역을 나눠줘야한다.
1 | <script> |
0
1
2
1 | <script> |
왜 error가 아닐까?
1 | <script> |
1 | ab: console.log('123') |
jump구문은 jump가 시작하는 문장 블럭의 가장 처음으로 가게 되어있다.
자바스크립트의 label 스펙은 자바의 label 스펙과 동일히다
레이블은 자바스크립트의 3.1버전때부터 있었던 스펙
switch의 문법적 요소를 확인해보자.
:
switch는 특별한 레이블 영역을 사용할 수 있는 공간을 만들어주는 문법이라고 생각해도 된다.
우리는 switch 괄호안에 있는 값의 평가된 것을
런타임에 평가해서
case에 있는 값과 일치하는 label로 보낼 수 있는
특수한 레이블 구문을 만들 수 있는 switch문이라는 것을 알 수 있다.
그 안에 있는 label은 우리가 알고 있는 label과 동일하게 작동한다.
case문 안에서 break를 안쓰면 그 다음 case문이 실행되는 현상
1 | <script> |
언어마다 스페셜 label block 해석 방식이 다르다.
1 | <script> |
자바스크립트에 case문은 runtime에 해석을 한다.
값에 대한 routing이 정적인 경우 값에 대한 routing에 더 우선순위가 높다.
1 | <script> |
switch구문이 runtime에 해석된다는 것은 뭐냐?
한줄씩 순차적으로 실행된다.
잘못된 점이 있으면 댓글 부탁드립니다 :)
서론
한 언어로 여러 프로젝트를 만들다 보면, 공용으로 사용되는 모듈들이 자연스럽게 생성된다. 비즈니스 코어를 모듈화할 수 있고, 또는 언어도 같고, api를 공유하는 프로젝트가 2벌 이상일 경우 http client만 모아있는 모듈을 따로 분리해서 공용화할 수도 있을 것이다. 이렇게 같은 공용 컴포넌트, 공용 모듈을 만들어서 공유할 수 있는 시스템이 구축된다면 공용으로 사용하고 있는 모듈에서 이슈가 생길 경우 작업은 한 번만 이루어 질 수 있기 때문에 생산성이 높아지고, 관리가 용이해진다.
git의 submodule을 사용하면 프로젝트 간 공용 모듈을 공유할 수 있다.
이 포스트에서는 submodule에 대해서 간단하게 다룰 것이다. 예시는 react + typeScript 기반이다.
부모 프로젝트에서 자식프로젝트의
validation class를 사용해 볼 것이다.
1 | npx create-react-app submodule_parent --scripts-version=react-scripts-ts |
App.tsx파일에서 form을 생성하여, input의 글자가
Email 형식이 아니라면 fail, Email 형식이면 pass 워딩을 보여주는 UI를 만들 것이다.
1 | // App.tsx |
email validation 로직은 공용 모듈로 분리해보자.
1 | mkdir submodule_child |
해당 폴더에 validation class를 만들었다.
현재 예시로 든 부모 프로젝트는 src 아래의 ts파일을 컴파일하도록 설정해놓았다. (src 밖의 ts파일은 컴파일하지 못함.) 만약 js파일로 공용 모듈을 만든다면 상관없지만, ts로 만든다면, src 하위에 submodule을 관리하는 폴더를 두도록 해야 한다. (혹은 경로에 상관없이 tsconfig파일에서 inlcude에 포함하면됨)
1 | // validation.ts |
공용으로 사용할 class을 만들었고, push 한다.
1 | git commit -am "first init" |
1 | git submodule add <자식 프로젝트 repository> |
추가가 되면 자동으로 .gitmodules
파일이 생성되고, 해당 경로에 submodule파일이 fetch된다.
.gitmodules
파일에는 프로젝트에서 관리하고 있는 서브모듈 목록에 대한 정보가 들어있다..gitignore
파일처럼 버전 관리된다.1 | [submodule "src/submodule_child"] |
깃 크라켄이라는 git client app을 사용하고 있는데, 해당 옵션에도 추가된 것을 확인할 수 있다.
1 | import * as React from "react"; |
코드스피츠 강의 정리록
철학/가치/동기
컴퓨터가 뭘까?
프로그램이 뭘까?
lint 타임에서 에러를 잡는게 제일 좋다!
당근컴파일 타임이 없어서 런타임이 중요
런타임은 메모리에 적재하여 실행하는 것
명령 하나당, 2번과 3번의 반복
메모리에 적재된 프로그램을 cpu가 소개한다. (노이만 머신의 구조)
프로그램 안에서 무슨일이 일어나는지 생각해보자.
데이터 부분의 메모리가 어떻게 움직이는지.
참조의 참조를 왜 쓰는지를 배우는게 핵심
고유한 번호를 주소로 갖는 블럭체계로 되어있다.
블럭을 나타내는 주소는 몇자리일까? => 64bit인지 32bit인지
(포인터 개념)
A = "TEST"
&A = 11
(C언어에서 주소값의 변수 앞에 &
를 사용한다.)
B = &A
*B = "TEST"
직접참조의 위험성
- 어떤 변수를 외부에 공개할 때
- 사용처를 확정지을 수 없다.
- 누가 어떻게 쓸지 모른다.
- 통제권을 벗어난다.
C = B, D = B, ...
: C와 D는 B를 바라보고있다.
B의 배신..B = &K
: 주소값이 바꾸었다.
double dispatch를 통해 해결할 수 있다.
1 | B = { value: &A, V: 3 } |
B가 직접참조하지않고, 간접적으로 참조하게 만들었다.
Dispatch: 주소로부터 값을 얻는 행위
B가 배신을 때려도 대응할 수 있다.
자바스크립트는 아래의 큰 3가지 카테고리로 나눌 수 있다.
문
이라는 개념이 없다.문을 나누는 기준에는 2가지가 있다.
공문, 식문, 제어문, 선언문
for(var i=0; i<5; i++);
=> 에러가 없다.;
단문, 중문
if(true);
if(true) a = 3; else b = 5
if (true) a=3; else if (a > 2) b = 3; else b =5;
if (true) a=3; else {if (a > 2) b = 3; else b =5;}
3;5;6;
프로그래밍: 메모리에 적재되어있는 명령어의 연쇄(flow)
Sync Flow / Flow Control / Sub Flow
그밖에도 외부활동도 최소 1가지는 하였다. 사내분들 이외의 분들도 만나고 싶었고, 커뮤니티도 참여하고 싶었기 때문이다.
예전만큼은 아니지만, 종종 외주작업도 들어오곤 했는데, 이젠 점점 줄이는 추세로 갔다. 아무래도 지금은 선택과 집중을 해야 했기 때문에..
업무는 다양하게 요청 들어왔다.
내가 잘 구현할 수 있는 부분도 있었고, 생소한 기술을 사용해야 하는 부분도 있었다. 생각지 못한 버그들을 맞닥드릴 때도 있었다. 혼자서 하고 싶은 작업만 했다면 이런 이슈들은 만나보지 못했을 것이다.
경험해보지 못했던 버그들을 고치거나, 기능을 구현해야 할 때, 그것을 공부하고 블로그에 정리하는 일은 뿌듯함과 성취감을 가져다 주곤 했다. 또한 아직 부족한 부분에 대해서도 인지할 수 있게 되는 계기가 되었다.
일주일 중 70프로를 회사 동료들과 함께 보낸다.
부정적인 시선으로 본다면, 우물 안 개구리가 될 수도 있고, 커뮤니티의 영역이 좁아질 수 있었기 때문에 부담 없는 외부활동을 하고 싶었다. 꼭 오프라인 활동을 하지 않아도 말이다. 체력이 약해진 터라 외부활동은 최대한 자제하고 ㅎㅎ 시간을 많이 뺏을 것 같은 활동도 우선은 고려하지 않았다. 아직 공부에 투자를 많이 해야 할 시기이기 때문.. 온라인으로 활동할 수 있는 커뮤니티를 찾다가 우연히 개발자 글쓰기 모임을 알게 되어 지금까지 꾸준히 참여 중이다.
외부활동의 장점은 나를 되돌아볼 수 있다는 점이다. 회사에서 잠시 한발자국 물러나 나를 바라볼 수 있는 잠깐의 시간을 가질 수 있도록 도와주기 때문에, 일정 기간마다 자기 객관화를 할 수 있도록 도와준다. 그리고 글쓰기 습관이 붙은 덕분에 2018년에는 45개의 글을 작성할 수 있게 되었다. ( 글또 1기 회고글 )
2018년도는 여러 면에서의 적응을 위해 내면을 깊게 들여다보지 못했다. 때문에 힘들 때 자주 흔들리곤 했는데, 그때마다 why를 외쳤다. 초심을 되돌아보고, 앞으로 어떤 방향으로 나아갈지 간략하게라도 정리를 하곤 했다. 자, 그래서 난 어떤 개발자가 되고 싶은가. 사실 제일 core는 내가 만든 기능으로 타인에게 도움 주기다. 한 번에 이룰 수 없다는 걸 알기 때문에 롱런을 위해서 재미있게 나아가려고 한다. 자연스럽게, 실력을 쌓으면서 재미와 흥미를 느낄 수 있는 부분은 뭐가 있을까로 고민하게 되었다.
사실 이런 계획은 이렇게 글이나 혹은 다른 이에게 말로써 이렇게 할 것이다를 얘기하지만, 실제로 실행에 옮기기에는 많은 의지와 시간이 필요하다. 이렇게 정리하는 나도 ㅎㅎ 스스로에게 살짝 의구심은 들지만, 구체적으로 정리하는 것만으로도 실행의 동기를 구체화 시켜준다.
무튼, 서론이 길었지만, 올해는 앞으로의 계획 중 하나라도 성취할 수 있도록 실행에 옮겨 스스로에게 보여주고 싶고, 잘 나아가고 있다고 말해주고 싶다.
다른말로 antd 파해쳐보기.
최근들어 antd를 프로젝트에 적용해 보았는데, antd에서 정리해둔 디자인 시스템의 원칙에 대해서 이해하고 코드를 분석해볼 필요가 있다고 생각했다. 이는 추후 antd를 적용하지 않아도, 기본 뼈대를 잘 설계할 수 있도록 도와줄 수 있다고 생각한다.
두말하면 잔소리.. 커뮤니케이션도 중요하지만 실력도 당연히 중요..
올해는 알고리즘을 꾸준히 풀어보려고 한다!!
스스로에게 증명하는 해
라는 키워드에서 가장 중요한 할 일 중에 하나이다. 올해는 내가 재밌어하는 분야(마블, 해리포터, 반지의 제왕..)를 믹스하여 재밌는 서비스를 만들어 보고 싶다.
실제 사용할 수 있는 수준까지!
리액트 + 타입스크립트로 프로젝트를 진행하면서 재밌는 이슈에 많이 부딪하고 있다. 그래도 재밌다고 느낀 이유는 부딪힐 때마다 해결 방법을 타입스크립트에서 제공해줬기 때문..
이슈 중에 하나는, 비동기 처리를 promise
와 async
await
를 사용하여 작업하고 있는데, 리턴값의 타입을 명시하기가 시점에 따라 달랐기 때문에 실행 시점에 타입을 명시하고 싶었다. 처음에는 예상되는 타입을 await를 받는 변수에 타입을 명시했는데 제네릭은 이를 해결할 수 있는 방법이었다.
*제네릭은 선언 시점이 아니라 생성 시점에 타입을 명시하여 하나의 타입만이 아닌 다양한 타입을 사용할 수 있도록 하는 기법이다. *한 번의 선언으로 다양한 타입에 재사용이 가능하다는 장점이 있다.
즉, 선언 시점에서는 제네릭으로 타입을 받을 부분을 뚫어놓고(?) (템플릿화 <T>
) 실행 시점에 제네릭으로 타입을 명시하는 것이다. 실행 시점에 제네릭으로 타입을 명시하게 되면, <T>
로 뚫어놓은(?) 템플릿에 타입이 명시되면서, 실행 시점에 맞는 타입을 정의할 수 있다. 마치 함수에서 인자를 받는 형태와 비슷하다.
너무 나만의 언어로 설명한 거 같으니.. 코드를 봅시다!
T
는 제네릭을 선언할 때 관용적으로 사용되는 식별자로 타입 파라미터(Type parameter)라 한다. T는 Type의 약자로 반드시 T를 사용하여야 하는 것은 아니다.
2번은 공식문서에 있는 내용이니 넘어가도 된다.
제네릭 없이 간단한 identity function을 만들어보자.
1 | function identity(arg: number): number { |
any 타입을 사용할 수도 있다.
1 | function identity(arg: any): any { |
any를 사용할 때는 arg가 모든 타입을 받을 수 있기 때문에 공용적으로 사용 가능하지만, 어떤 값을 반환 할지에 대한 정보는 알 수가 없다. 만약 인자와 반환자의 타입을 같게 하고, 이를 공용적으로 사용하고 싶을 경우 제네릭을 사용하면 된다.
1 | function identity<T>(arg: T): T { |
호출 시 아래처럼 제네릭으로 명시하면 된다.
두 번째 줄은 제네릭으로 명시하지 않았는데, 이는 인자로 넣어지는 ‘myString’타입으로 인해 컴파일러가 자동으로 T의 타입을 정의하기 때문이다.
1 | let output = identity<string>("myString"); |
identity 함수의 타입을 명시할 때도 제네릭을 명시할 수 있다.<T>(arg: T) => T
1 | let myIdentity: <T>(arg: T) => T = identity; |
위의 코드를 인터페이스로 표현한다면?
1 | interface GenericIdentityFn { |
재밌게도!! 인터페이스에서 제네릭을 명시하게 할 수도 있다.
1 | interface GenericIdentityFn<T> { |
클래스에서도 제네릭을 명시할 수 있다.
1 | class GenericNumber<T> { |
타입스크립트를 리액트와 함께 사용할 때 자주 볼 수 있는 패턴이다.
1 | class Component extends React.Component<Props, State>{ |
제네릭은 인터페이스를 상속받을 수도 있는데, 제네릭을 명시한 함수에서 특정 타입이 들어올 것을 예상하고 로직을 작성해야 할 경우에 인터페이스를 상속받아 사용 가능하다.
1 | interface Lengthwise { |
typeScript deep dive 문서를 보면, 사람들은 제네릭을 heck스러운 방법으로 사용할 때가 있다고 한다.
개발자가 제네릭을 사용할 때! 어떤 부분을 강제할 것인지에 대해 제대로 설명하지 못한다면 제네릭을 사용할 필요가 없다고 한다.
아래 코드를 보면, 제네릭을 명시했지만, 인자 하나에서만 사용되고 있다.
이렇게 하나의 인자를 위해서 제네릭으로 받는 상황에서는 제네릭은 쓸모없는 무의미한 명시다.
1 | declare function foo<T>(arg: T): void; |
아래의 상황에서는 제네릭의 T가 리턴 값으로 한 번만 사용되었다.
type assertion 방법과 딱히 다르지 않다.
오직 리턴 값 한 번만 사용하기 위한 제네릭은 타입 안정성 측면에서 어셜션보다 나은 방법은 아니다.
1 | declare function parse<T>(name: string): T; |
그렇다면 어떤 상황에 사용해야 제네릭을 적합하게 사용하는 것일까.
api로 응답 값을 받을 때 제네릭을 사용하면 굉장히 편리하게 사용할 수 있다.
fetch로 github 정보를 받아오는 함수가 있다고 가정하자. (async, await 사용)
1 | const githubUser = await fetchGithubInfo() |
제네릭을 몰랐을 때는 아래처럼 써주었다…
1 | const githubUser: GithubRep | undefined | null = await fetchGithubInfo() |
이런 말도 안 되는 8ㅅ8
githubUser에는 await 함수가 할당되어있는 상황이기 때문에 Promise 타입을 명시해야 맞는 상황.
때문에 아예 fetchGithubInfo에서 제네릭으로 타입을 받게 변경하였다.
1 | const fetchGithubInfo = async <T>(): Promise<T | null> => { |
1 | const githubUser= await <GithubRep>fetchGithubInfo() |
깔끔! 추후에는 아예 ajax 콜 모듈화한 함수에서 제네릭을 자주 사용하게 되었다.
참고
]]>오류가 있다면 언제든지 지적해주세요.
코드: https://github.com/feel5ny/redux-observable-practice
https://www.youtube.com/watch?v=AslncyG8whg
Not familiar with Observables/RxJS v6?
redux-observable requires an understanding of Observables with RxJS v6. If you’re new to Reactive Programming with RxJS v6, head over to http://reactivex.io/rxjs/ to familiarize yourself first.
redux-observable (because of RxJS) truly shines the most for complex async/side effects. If you’re not already comfortable with RxJS you might consider using redux-thunk for simple side effects and then use redux-observable for the complex stuff. That way you can remain productive and learn RxJS as you go. redux-thunk is much simpler to learn and use, but that also means it’s far less powerful. Of course, if you already love Rx like we do, you will probably use it for everything!
If you’re not already comfortable with RxJS you might consider using redux-thunk for simple side effects and then use redux-observable for the complex stuff.
“만약 당신이 아직 rxjs에 익숙하지 않다면, 간단한 사이드이팩트용으로는 redux-thunk를 사용하는 걸 고려하고, 복잡한 stuff에서는 redux-observable을 사용하는 것이 좋습니다.” 링크
그래서 한번 공부해보기로 했다.
1 | function (action$: Observable<Action>, state$: StateObservable<State>): Observable<Action>; |
It is a function which takes a stream of actions and returns a stream of actions. Actions in, actions out.
에픽함수는 액션스트림을 가져가고, 액션스트림을 반환하는 함수이다.
간단하게 말하자면, action 객체를 store에서 ActionObservable로 얻게되는데,
에픽에서는 액션 옵저버블을 스토어에서 받아서 추가적인 처리후 다시 옵저버블로 반환할 수 있다.
추가적인 처리에는 rxjs의 operator 등을 사용한다.
createEpicMiddleware
를 사용한다.1 | // store.ts |
1 | // createEpicMiddleware : index.d.ts |
깃헙에서 정보를 받아오는 ajax요청 처리를 해보자.
액션파일에는
FETCH_USER
FETCH_USER_FULFILLED
FETCH_USER_REJECTED
FETCH_USER_CANCELLED
1 | // 액션 타입 |
1 | // 액션 함수 |
1 | const users = ( |
1 | export const fetchUserEpic = ( |
참고
]]>[📕 퀵스타트 Rxjs]를 보고 메모한 부분을 정리했습니다.
RxJS is a library for composing asynchronous and event-based programs by using observable sequences.
RxJS는 Observable를 사용하여 비동기 및 이벤트 기반 프로그램을 작성하기 위한 라이브러리이다.
(범용적인 데이터 플로우 솔류션을 지향하는 라이브러리라고 책 저자가 정의함)
목표: 페이지를 클릭했을 경우 event.currentTarget
정보를 콘솔로 출력해보자.
1 | const {fromEvent} = rxjs; |
fromEvent(target: EventTargetLike, eventName: string, selector: function): Observable
click 옵저버블을 구독하고, 옵저버블에서 데이터가 전달되면 옵저버함수가 받는다.
이는 addEventListener를 통한 이벤트 핸들러 등록과 유사하다.
둘의 차이점은 브라우저를 통해 전달되는 이벤트 정보를 Observable로 변환하는 작업을 추가로 한다는 점
실제 우리가 필요한 정보는 click이 아니라 click이후의 currentTarget
정보
pluck 오퍼레이터를 이용하자.pluck(properties: ...string): Observable
pluck은 사전적으로 ‘~을 뽑다’라는 의미이다. 추출할 속성들을 ‘문자열’로 지정할 수 있다.
pipe 오퍼레이터를 사용하여 파라미터로 전달된 오퍼레이터들이 적용된 새로운 Observable 인스턴스를 반환한다.
1 | const {fromEvnet}= rxjs; |
cf__1. RxJS에서 pipe 오퍼레이터를 적용하여서 도트 체이닝없이 오퍼레이터를 받는다.
pipe는 처리되어야할 작업들을 순차적으로 받아서 처리한다.pipe(operations: ...): Observable
1 | // 도트체이닝 |
Observable.prototype
에 사용하는 모든 오퍼레이터가 추가된다.1 | const a = [ |
from(ish: ObservableInput, mapFn: function, thisArg: any, scheduler: Scheduler): Observable
1 | const {from} = rxjs; |
시간을 축으로 연속적인 데이터를 저장하는 컬렉션을 표현한 객체이다.
Observable은 데이터를 제공하는 소스를
Observer에게 전달한다.
이를 스트림(stream)이라고 부른다.
Observable을 생성 및 조작하는 함수를 오퍼레이터(operator)라고 한다.
오퍼레이터는 Observable을 생성하기도 하고,
각각의 Observable을 연결하기도 한다.
Observable을 분리하거나 합치기도 한다.
오퍼레이터는 현재의 Observable 인스턴스를 기반으로 항상 새로운 Observable 인스턴스를 반환한다.
Observable에 의해 전달된 데이터를 소비하는 주체이다.
Observers는 next, error, complete함수를 가진 객체를 가리킨다.
Observable에 의해
데이터가 전달될 때는next함수가 호출되고
에러가 발생했을 때는 error함수,
데이터 전달이 완료되었을 때는 complete함수가 호출된다.
Observer과 Observable은 subscribe 메소드를 통해 연겨로딘다.
subscrie는 Observer를 파라미터로 받는다.
Observer객체를 전달하는 subscribe 사용 예
1 | const observer = { |
next 콜백함수를 전달하는 subscribe 사용 예
1 | click$.subscribe(x => console.log('Observer가 Observable로 부터 받은 데이터: ' + x)) |
next, error, complete 콜백 함수를 전달하는 subscribe 사용 예
1 | click$.subscribe( |
Observable.prototype.subscribe의 반환값
Subscription은 자원의 해제를 담당
unsubscribe 메소드를 호출하여 자원해제 가능
1 | ... |
RxJS를 사용하여 개발할 경우 프로세스는 대부분 다음과 같은 과정
1기를 지내면서 느낀 건..2주동안 글 하나를 써야 하는 것은 생각보다 많은 노력이 필요하다는 것. 게다가 노출되는 글이기에 좋은 글을 써야겠다는 약간의 강박?이 생겨 글쓰기를 시작도 못한 때도 있었다.
글또 기간 동안 쓴 글을 분류해보니 이러했다.
(기준: 목적)
(기준: 분야)
처음에는 습관들이기가 참 어려웠다. 나름 예전에 네이버 블로그를 했었는데도 말이다. 내 개인 일기장에 쓰는 글이 아닌 SNS에 글을 쓴다는 건 글을 잘 써서 올려야 한다는 강박에 사로잡히게 되는데, 글또 초반에도 그랬었다. 그러다 책 메모, 요약 글을 올리면서 서서히 글쓰기가 재밌어졌고, 출근 때도 블로그 글들을 복습하는 습관도 갖게 되었다. 내가 쓴 글에 작품처럼 애정이 간다고 해야 할까.
잘 정리한 건가? 잘 읽히나? 오타는 없나?
구글 애널리틱스에서 자연어 검색 메뉴를 자주 보게 된다. 어느 날 갑자기 pv가 늘어나면 메일로도 알려주기 때문에 보는 쏠쏠한 재미가 있었다.
> 2018년 2월 ~ 2018년 8월 26일까지순위별로 보면
Hexo의 Humen이라는 테마인데, UI가 70%로 마음에 들고 30%는 고치고 싶은 곳이 있다. 우선 내가 쓰기에도 불편한 부분을 고침
앞으로 추가하고 싶은 것
블로그 꾸미기는 나의 소확행 ~
(기준: 목적)
1번 > 2번, 3번
비율로 쓸 예정이다.(기준: 분야)
현재 확실히 계획된 부분은 이렇다.
📚: 공부하자! 내 스타일로 메모
💡: 작업하다가 삽질해서 내 것이 된 지식을 정리하자.
🏃: 세미나 다녀왔습니다.
참고
의식적 연습하기
📒 인사이드 자바스크립트 중 메모해야할 부분만 적었습니다.
함수형 프로그래밍에 대해서 더 깊게 배우길 원한다면 Lisp나 Haskell과 같은 언어를 공부하자.
TL;DR
함수의 조합으로 작업을 수행함을 의미한다.
이 작업이 이루어지는 동안 작업에 필요한 데이터와 상태는 변하지 않는다는 점.
함수가 바로 연산의 대상이 된다.
FP의 목적
1 | f1 = encrypt1; |
순수함수 Pure fucntion
외부에 영향을 미치지 않는 함수
1 | function getCurrentValue(value){ |
부원인과 부작용
고계 함수 Higher-order function
함수를 또 하나의 값으로 간주하여 함수의 인자 혹은 반환값으로 사용할 수 있는 함수
주요키워드
순수함수도 있지만,
특정 작업을 수행하는 여러가지 명령이 기술되어 있는 함수도 있다.
=> 프로시저라고 한다. Procedure
자바스크립트는 다음을 지원하기때문에 함수형 프로그래밍이 가능
1 | const f1 = function(input) { |
명령형 프로그래밍으로 작성된 코드.
1 | function sum(arr){ |
함수형 프로그래밍
1 | function reduce(func, arr, memo){ |
명령형 프로그래밍
1 | function fact(num) { |
혹은 재귀호출
1 | function fact(num) { |
앞서 연산한 결과를 캐시에 저장하여 사용하여 함수를 작성한다면 성능 향상에 도움이 된다.
1 | const fact = function(){ |
memoize
메모이제이션 패턴
data : 해당 엘리먼트에 JavaScript Type의 value를 저장할 수 있으며, 값으로 저장되어 있는 데이터를 읽습니다.
data-XXX
Function.prototype
에 메모이제이션 패턴을 사용할 수 있는 함수를 넣으면 사용가능하다.jQuery에서는 cleanData라는 메서드를 제공한다.
1 | function Calculate(key, input, func){ |
Function 프로토타입에 memoization()
함수 넣기
1 | Function.prototype.memoization = function(key) { |
메모이제이션 기법 사용한 함수형 프로그래밍
1 | const fibo = function(){ |
팩토리얼 함수와 패턴과 거의 비슷하다.cache의 초기값
과 함수를 재귀 호출할 때 산술식
만 다르다.
=> 팩토리얼과 피보나치 수열을 계산하는 함수를 인자로 받는 함수를 모듈화할 수 있다.
1 | const cacher = function(cache, func){ |
Function.prototype.apply
왜 이름이 apply?
func.apply(Obj, Args)
와 같은 함수 호출을 ‘func 함수를 Obj객체와 Args인자 배열에 적용시킨다’라고 표현할 수 있다.
cf__3. 함수 호출
괄호 연산자 대비 call/apply를 사용할 때의 장점은
함수가 실행되는 컨텍스트를 지정할 수 있다는 점이다(this의 값).
이러한 형태는 고차 함수, 특히 이러한 고차 함수가 나중에 실행되는 함수를 소비할 때 볼 수 있다.
Function 프로토타입에서 bind 메소드의 내부는 call/apply의 훌륭한 예다.
1 | // Possible implementation of bind using apply |
특정 함수에서 정의된 인자의 일부를 넣어 고정시키고,
나머지를 인자로 받는 새로운 함수를 만드는 것을 의미한다.
1 | function calculate(a,b,c){ return a*b+c }; |
자바스크립트에서 기본으로 제공하지 않기 때문에 Function.prototype에 정의하여 사용할 수 있다.
1 | Function.prototype.curry = function() { |
커링에서 함수의 인자를 arguments 객체로 조작할 때 이 메서드를 이용하여 배열로 만든 후 손쉽게 조작 가능
1 | Function.prototype.bind = function (thisArg){ |
1 | const print_all = function(arg){ |
특정함수를 자신의 함수로 덮어쓰는 것
OOP에서 다형성을 위해 오버라이드를 지원하는것과 유사하다.
1 | function wrap(object: Object, method: string, wrapper){ |
jQuery 1.0의 each()
1 | function each(obj, fn, args){ |
1 | Array.prototype.map = function(callback){ |
1 | Array.prototype.reduce = function(callback, memo){ |
참고
]]>📒 인사이드 자바스크립트 중 메모해야할 부분만 적었습니다.
1 | function Person(arg) { // 클래스이자, 생성자의 역할을 함. |
1 | const you = new Person("Gray"); |
1 | function Person(arg){ |
프로토타입 메서드를 만드는 루틴을
함수체인의 더 상위인 Function 프로토타입에 method라는 이름으로 만들어놓고
재사용하는 방법도 있다.
1 | Function.prototype.method = function(name, function) { |
1 | function create_object(o) { |
인자로 들어온 객체(o)를 부모로 하는
자식 객체(F)를 생성하여
반환한다.
=> 프로토타입의 특성을 활용하여 상속을 구현하는것 = 프로토타입 기반의 상속
예시
1 | function create_object(o) { |
1 | me.setAge = function(age) {...} |
위의 방식으로 확장할 수 있지만, 코드가 지저분해질 수 있다.
extend()라는 이름의 함수로 객체에 자신이 원하는 객체 혹은 함수를 추가시킨다.
__jQuery의 extend 함수
1 | jQuery.extend = jQuery.fn.extend = function(obj: 자식, prop: 부모) { |
jQuery.fn
은 jQuery의 프로토타입var elem = new jQuery(...); elem.extend()
형태로 호출가능ob[i] = prop[i];
은 얕은 복사 (shallow copy) => 참조값을 복사하는 경우 영향이 생긴다.1 | // jQuery extend 함수 중 일부 |
1 | const person = { |
1번은 객체의 상속이었고, 지금은 클래스의 역할을 하는 함수를 상속하는 것을 설명한다. (컨텍스트 상속)
1 | function Person(arg) { this.name = arg;} |
you는 Person의 인스턴스 (name: JoyKim)
Student의 프로토타입은 you를 가리킨다.
me는 Student의 인스턴스
1 | function Student(arg){ |
me객체에서 setName을 호출하면 프로토타입체이닝에 의해서 Person까지올라간다.
이 로직의 단점은 me의 prototype이 Student.prototype이고, 이는 곳 you를 가리킨다는 것인데,
이렇게 되면 me가 you의 자식 개념이 되면서 잘못된 설계가 된다.
me와 you의 독립성을 위해서 중간 역할을 해주는 프로토콜 빈 함수 F()를 추가한다.
1 | function Person(arg) { this.name = arg;} |
me는 Person을 상속받은 Student의 인스턴스이고
you는 Person의 인스턴스.
위 로직을 모듈화 시키면..(by.스토얀 스테파노프[JavaScript Pattersn])
1 | const inherit = function(Parent, Child){ |
클로저는 F()함수를 지속적으로 참조한다.
F()는 가비지 컬렉션의 대상이 되지 않고 계속 남아 있다.
이를 이용해 함수 F()의 생성은 단 한 번 이루어지고 inherit함수가 계속해서 호출되어도 함수 F()의 생성을 새로 할 필요가 없다.
public
, private
, protected
멤버를 선언함으로써 해당 정보를 외부로 노출시킬지 여부를 결정)1 | const Person = function(arg) { |
1 | // 모듈패턴 |
1 | const Person3 = function(arg){ |
함수의 프로토타입 체인
extend 함수
인스턴스를 생성할 때 생성자 호출을 이용해서 자바스크립트로 클래스 기능을 하는 함수 만들기
subClass함수는
변수 및 메서드가 담긴 객체를 인자로 받은
부모 함수를 상속받는 자식 클래스를 만든다.
부모함수는 subClass() 함수를 호출할 때 this 객체를 의미한다.
1 | const SuperClass = subClass(obj); // 상속받을 클래스 |
이처럼 SuperClass를 상속받는 subClass를 만들고자 할 때,
SuperClass.subClass()의 형식으로 호출하게 구현한다.
참고로 최상위 클래스인 SuperClass는 자바스크립트의 Fucntion을 상속받게 한다.
1 | function subClass(obj){ |
1 | function subClass(obj) { |
자식 클래스는 child 라는 이름의 함수 객체를 생성함으로써 만들어졌다.
1 | for (let i in obj){ |
hasOwnProperty
인자로 넘기는 이름에 해당하는 프로퍼티가 객체 내에 있는지를 판다.
프로토타입 체인을 타고 올라가지 않고 해당객체 내에서만 찾는다는 것에 유의
1
2
3
4
5 o = new Object();
o.prop = 'exists';
o.hasOwnProperty('prop'); // true
o.hasOwnProperty('toString'); // false
o.hasOwnProperty('hasOwnProperty'); // false
클래스의 인스턴스가 생성될 때, 클래스 내에 정의된 생성자가 호출돼야하다.
부모 클래스의 생성자 역시 호출되어야한다. (초기화를 위해서)
1 | const child = function() { |
1 | const SuperClass = subClass(); |
instance 생성시 SuperClass 생성자가 호출되지 않는다.
=> 부모클래스의 생성자를 호출하는 코드를 재귀적으로 구현하여 해결한다.
1 | const child = function() { |
최종
1 | function subClass(obj){ |
By Joy.
🔥 코드스피츠 수업을 수강하면서 복습한 내용을 정리했습니다.
아직 정리중..
판마지막 판이 몇 판일까? = 몇 판까지 있을까?
속도
** 판마다 속도가 증가한다.**
** 속도는 어떤 객체가 가져가야할까?**
1 | // Object.assign 쓰기 번거로워서 함수 만들긔 |
1 | const Stage = class { |
1 | const Score = class { |
프로그래밍의 실체는 수행해야하는 job이 누구의 역할과 책임으로 넘어가야하는지를 의사결정하는 행위.
객체지향에서는 컨텍스트라는 방법이 있다.
인스턴스별로 컨텍스트라는 유지한다. (컨텍스트: 인스턴스마다 고유하게 부여되어 있는 메모리).
*함수에서 값을 가져오는 방법 2가지. *
1 | const Score = class { |
현재는 약한 바인딩.
add 함수 호출시에만 임시적으로 외부 인자로 들어오기때문에
But,
하나의 게임 안에서는
스테이지와 스코어를 동시에 소유하고 바뀌지 않는다.
도메인을 바라보고 어디 쪽의 역할이 맞는지 항상 의사결정을 해야한다.
1 | const Score = class { |
코드는 여러분들이 모국어로 쓰지 않기 때문에
동작만 하면 다 똑같은 코드로 보인다.
코드도 언어이기 때문에 한국어의 미묘한 늬앙스를 다양한 형사와 동사로 표현하는 것처럼,
코드도 동작해도 표현방법에 따라서 늬앙스를 다 표현할 수 있다.
cf__2 연산은 데이터로 바꿀 수 있다.데이터 하나로 연산화 시킴
or 데이터 2개로 연산비용을 낮춤.
1 | // Block 클래스 : 카테고라이제이션 하는 중.. |
1 | class extends Block { |
1 | class extends Block { |
rotation은 부모클래스인 Block에서 관리
자식이 부모의 속성을 갖는 것은 은닉을 깨고 있는 것
this.rotate
로 접근하고 있다.this.rotate % 2
부모의 rotate 정의에 자식이 맞추고 있다.코드의 책임, 역할을 의인화 시켜서 생각하는 것이 좋다.
getBlcok()을 호출할 때마다 배열을 매번 생성하고 있다.
다시 개선
1 | const Block = class { |
렌더러는 stage, score, block을 몰라도, data만 알아도 되는 구조
1 | const Renderer = class { |
Template Method Pattern
어떤 작업 알고리즘의 골격을 정의한다. 일부 단계는 서브 클래스에서 구현하도록 할 수 있다. 템플릿 메서드를 이용하면 알고리즘의 구조는 그대로 유지하면서 특정 단계만 서브 클래스에서 새로 정의하도록 할 수 있다.
1 | // Array를 상속 받는 이유는 형을 확인하기 위해 강제로 만듦. |
es6는 클래스 내부에서 this를 바꿔 줄 수 있다.
1 | // utility |
1 | const TableRenderer = class extends Renderer { |
변수 사용시 한 번 밖에 사용되지 않는데 변수로 잡는 것은 사실은 중복
for와 forEach 중 어떤걸 사용할까?
언어스팩에서 정의되어있는 메서드를 사용하자. forEach
성능문제는 우선 고려하지 말자.
1 | const CanvasRenderer = class extends Renderer{ |
참고자료
https://www.bsidesoft.com/?p=2827
https://github.com/abhbtbb/tetris1
🔥 코드스피츠 수업을 수강하면서 복습한 내용을 정리했습니다.
OOA, OOD까지만의 내용만 다루었습니다. 강의와 추가로 찾아본 자료와 섞여있습니다.
소프트웨어를 개발하는 하나의 방법론으로
모든 소프트웨어 시스템의 주요 기본요소를
사물을 가리키는 객체와 그 객체들을 하나의 집합으로 묶은 클래스로 구성하는
객체지향적인 분석과 설계 방법을 말한다.
객체지향적이란 것은 현실세계에 실재하는 사물, 즉 객체들을 지향한다는 것이다.
클래스는 추상,
오브젝트는 클래스가 실체로 만들어진 것
클래스
클래스는 표현 대상들의 공통적인 특징에 대한 서술(추상)을 말한다
추상
추상은 사용자가 구체적인 내용을 생각하지 않고도 사용할 수 있는 기능
오브젝트는 클래스의 인스턴스이다.
오브젝트는 instance of class => 클래스가 실체로 만들어진 것.
cf__ 다양한 용어지만 같은 뜻
데이터와 (data)
데이터를 다루는 방법을 (operation on data)
묶는 것
관련 있는 것을 묶어서 이름을 부여한 것 => 추상화
객체지향에서 객체끼리 지켜야할 최소한의 룰
은닉: 숨기다.
최대한 은닉하고
최대한 캡슐화해서 상대방과 대화한다.
하나의 클래스가 가지고 있는 특징들(데이터 + 조작)을 그대로 다른 클래스가 물려 받는 것
__proto__
)상속성의 계층을 따라서 각각의 클래스에 한가지 이름을 줄 수 있다.
같은 명령을 각기 다른 오브젝트에 줄 수 있다.
1 | Dog d; |
처음 만들어졌을 때 원형이 누구냐에 따라서 오버라이드 되어있거나 오버라이딩 된 속성을 반드시 만들어진 구상객체를 사용하도록 되어있다.
cf__ 메세지 전달 message passing
객체지향관점에서 프로그램은 오브젝트에 message를 보내는 것으로 실행
👇
👇
도메인 => 도메인 개념의 시각화 => 설계 객체를 구현
난감한 도메인을 만났을때 우리는 어떻게 데이터 분석을 해서 처리할 수 있는가
⇒ 데이터 분석의 결과가 객체지향이 될 수 있게 하는 것이 우리의 목표
분류를 일정한 기준으로 묶어 놓는 것.
디테일을 숨기고 카테고리의 특징만 뽑아내서 이해하게 된다.
현실세계에 있는 실물에서 내가 기억해야할 것들을 모아 놓은 것.
모델링에서 가장 중요한 것
카테고라이제이션으로 관리할 수 있나? 그냥 그룹화해서 관리할 수 있나?
본인이 역할(role)과 책임이 있나?
권한과 책임을 일치하게 나눌 수 있냐..
cf__설계시 유의해야할 점
DATA (프로토콜)
Render와 게임정보 사이의 프로토콜 역할
상호 간에 약속한 형태(프로토콜)를 끠어넣으면 둘 사이의 의존성이 줄어들게 된다.
프로토콜 = 의정서, 합의서, 약정서
게임본체와 렌더러는 서로 몰라도 되고, 프로토콜만 알면 된다.
Game 게임본체: stage + score + block + 범용패널 을 포함한다.
범용 렌더링 처리기 Renderer : 데이터를 받아서 그리는 역할
변화율에 따라서!변화율이 극심한 경우에는 중간에 반드시 프로토콜을 넣어주어야한다!
참고자료
OOAD : http://dollipolly.tistory.com/entry/OOAD-Object-Oriented-Analysis-Design
http://egloos.zum.com/nom3203/v/2502870
객체지향 : https://www.slideshare.net/plusjune/ss-46109239
🔥 코드스피츠 수업을 수강하면서 복습한 내용을 정리했습니다.
참고 : 렌더링 엔진 - 파싱
어떤 상황을 보고 구조적이고 재귀적인 형태로 파악을 할 수 있느냐,
데이터 분석을 할 수 있느냐..
<기호> ::= <표현식>
1 | A = <tag>body</tag> |
문자열을 읽어서 구조적으로 객체화 시켜 리턴하게 하고 싶다.
1 | interface Result { |
false
가 될때까지 loopC타입: 텍스트
다음 태그까지를 파악
1 | interface Result { |
curr
때문에 결합도가 올라가지만 어쩔 수 없는 부분역할을 인식하자마자!! 분리하자.
나중에 분리할 때는 이미 오염되어있어서 분리시키기 어렵다.
1 | const textNode = (input: string, cursor: number, curr: StackItem): number => { |
1 | interface Result { |
공통점을 찾아서 코드를 중복시키는 것을 피해야한다.
눈을 훈련해서 먼저 공통요소를 추상화 할 수 있는 능력을 키워야한다.
<img />
, open tag <div>
empty element가 더 간단해 보이므로 먼저짜긔
1 | const parser = input => { |
좋은 코드를 짜는 비밀은
머릿속에 맨톨모델이 그려지면 코드로 똑같이 표현되어야지 정상이다.
바른 데이터 모델링이 돼었으면
1 | let name, isClose; // 👈 공통 준비사항 층 |
케이스는 다 값으로 바꿀 수 있다.
위의 코드 형태
화이트리스 whitelist
‘안전’이 증명된 것만을 허용하는 것으로 ‘악의성’이 입증된 것을 차단하는 블랙리스트 보안과 상반되는 보안 방식 이다.
화이트리스트, 블랙리스트라는 용어 대신 ‘positive’와 ‘nagative’ 보안 방법으로 불려지기도 합니다.
1 | const idx = input.indexOf('>', cursor); |
분리 ~
1 | const idx = input.indexOf('>', cursor); |
(변수명을 이쁘게 쓰던, 컨벤션을 지키던)
코드가 리더블하다? Readable
1 | stack.push({tag, back:curr}); |
1 | ... |
css압축이나 javascript압축보다
html압축이 브라우저의 부하를 줄이는 방법
쓸데없는 노드생성을 줄인다.
1 | const elementNode = (input, cursor, idx, curr, stack) => { |
1 | const parser = input => { |
🔥 코드스피츠 수업을 수강하면서 복습한 내용을 정리했습니다.
공부 후에는 풀어서 쉬운 언어로 설명할 수 있도록 연습하자.
Tail Recursion
** 예시 *
1 | const sum = v => v + (v ? sum(v-1) : 0); |
인자로 옮겨서 스택메모리가 생기지 않도록 하였다.
1 | const sum = (v, prev = 0) => { |
&&
연산자||
연산자자바스크립트는 이미 ES6에서는 tail recursive를 지원하게끔 스펙으로 지정해놓았다.
JVM은 지원하지 않는다.
1 | const sum = (v, prev = 0 ) => { |
1 | const sum = (v) => { |
위 그림을 코드로 표현한다면..
1 | window.a = 3; // main flow의 전역: global |
1 | const a = 3; // main flow에 A |
1 | const a = 3; // main flow에 A |
리턴말고 yield를 사용한다. (언어마다 키워드가 다르다.)
자바스크립트에는 C# 문법이 많이 반영되어있다. (async await도..)
yield에서 끊어지고 리턴포인트로 돌아간다.
suspension
를 걸 수 있다.1 | const generator = function*(a){ |
1 | let result = 0; |
1 | let result = 0; |
다음의 코드는 구구단을 출력한다.
이를 만족하는 제네레이터를 작성하시오.
1 | const generator_Joy = function*(i, j){ |
1 | // 어떤 분의 의식의 흐름 |
🔥 코드스피츠 수업을 수강하면서 복습한 내용을 정리했습니다.
공부 후에는 풀어서 쉬운 언어로 설명할 수 있도록 연습하자.
1 | const routineA = b => { |
routine
이라고 부른다.참고 : http://webframeworks.kr/tutorials/translate/arrow-function/
인자
와 리턴
이라고 알고 있다.1 | const routineA= arg => { |
코드로 표현하면
1 | const routineA = arg => routineB(arg * 2); |
극단적인 예
코드로 표현하면
1 | const r1 = a => r2(a * 2); |
서브루틴 안에 서브루틴이 들어가면 기본적으로 이런 일이 일어난다.
값은 메모리상에서 전달할 때마다 복사되는 형태,참조는 메모리상에서 공유된 객체의 포인터만 전달되는 형식
POINT- 값이 넘어가면 복사된 값이 넘어가기 때문에 해당 루틴에서 값이 변화가 일어나도 main flow에서는 값에 영향을 주지 않는다.- 루틴에서 return 되는 값도 복사본이 넘어가기 때문에 main flow는 새로운 복사본을 받게 되는 개념이다.- 즉, main flow와 루틴 사이에는 **의존성이 낮아진다.**- **값의 정의는 언어마다 다르다.** - 문자열은 자바스크립트에서 값이지만 자바에서는 참조로 정의되고 있다. - 자바스크립트는 6개(es6 기준: number, string, boolean, undefined, null, symbol)- 하나의 루틴이 여러 flow를 상대하고 있어도 아무 문제가 생기지 않는다. - 복사본만 주고받기 때문에> 상태안정이라고 부른다. **State safe** - 수학적 프로그래밍의 기반이 된다. - 값을 컨택스트로 해서 함수형 프로그래밍을 하려고 한다. - 어디에서 누가 몇번을 부르던 상관없다. - 완전 수학적 함수라고 한다. - 때문에 처음 함수를 작성할 때 인자를 값으로 넘기는지부터 확인해보면 안전한 함수를 짤 수 있다.1 | const routine = a => a*2; |
1 | const routine = ref => ['a','b'].reduce( |
1 | const routine = ({a, b, ...rest}) => rest; |
spread 문법 (참고: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax)
1 | const routine = ref => { |
1 | const routine = ref => ({...ref, e:7}); |
spread연산자는 순서에 영향이 있다.
이전에는 hash map이였는데, linked hash map이됨.
객체를 넣는 순서가 보장이 된다.
Larry constantine_ Structured design
좋은 서브루틴이란 높은 응집도와 낮은 결합도를 갖도록 짜야한다!
A클래스 속성v가 변경되면 즉시 B클래스가 깨짐
1 | const A = class { |
Common클래스 변경 시 즉시 A,B클래스가 깨짐
1 | const Common = class { |
A, B 클래스는 외부의 정의에 의존함.
member의 json 구조가 변경되면 깨짐.
1 | const A = class { |
A클래스 내부의 변화는 B 클래스의 오작동을 유발
1 | const A = class { |
1 | const A = class { |
1 | const A = class { |
1 | const Util = class { |
1 | const Math = class { |
1 | const App = class { |
1 | const Account = class { |
1 | const Array = class { |
1 | const Account = class { |
높은 응집성을 갖게 되면 높은 커플링은 갖게된다.
결합도와 응집도의 조화를 목표로 로직을 짜야한다.
📒 인사이드 자바스크립트 중 메모해야할 부분만 적었습니다.
1 | function sum(){ |
함수가 호출되는 방식(호출패턴)에 따라 this가 다른 객체를 참조한다.(this 바인딩)
자신을 호출한 객체에 바인딩된다!
1 | const myObject = { |
자바스크립트의 모든 전역 변수는 전역 객체의 프로퍼티들이다.
(브라우저는 window, node는 global)
1 | const value = 100; |
부모함수의 this를 내부 함수가 접근 가능한 다른변수에 저장하는 방법이 사용된다.
1 | const value = 100; |
객체를 생성하는 방법
기존 함수에 new 연산자를 붙여서 호출하면 해당 함수는 생성자 함수로 동작한다.
일반 함수에 new를 붙여 호출하면 원치 않는 생성자 함수처럼 동작할 수 있다.
특정함수가 생성자 함수로 정의되어 있음을 알리려고 함수 이름의 첫 문자를 대문자로 쓴다.
생성자 함수에서의 this는 함수호출방식의 this 바인딩과 다르게 동작한다.
이를 이해하기 위해 생성자 함수의 동작방식을 이해하면 된다!
1 | const Person = function(name){ |
위 의 예시를 토대로 설명
__proto__
는 자신을 생성한 생성자 함수Person()
의 prototype 프로퍼티가 가리키는 객체를 1 | const foo = { |
대문자 표기 네이밍 규칙을 권장하나 휴먼에러가 발생 할 수 있기 때문에 다음과 같은 분기문이 있는 코드 패턴을 사용하기도 한다.
1 | // 강제로 인스턴스 생성하기 |
내부적인 this 바인딩 이외에도
this를 특정 객체에 명시적으로 바인딩 시키는 방법
함수의 부모 객체인 Function.prototype 객체의 메서드들이다.
apply()메서드를 호출하는 주체가 함수고,
apply() 메서드도 this를 특정 객체에 바인딩할 뿐
결국 본질적인 기능은 함수호출이라는 것이다.
1 | function.apply(thisArg, argArray) |
function
을 호출하라, 이때 this는 thisArg
에 바인딩해라.
1 | function Person(name, age, gender){ |
유사배열 객체에서 사용하는 경우
1 | function A(){ |
Array.prototype.slice를 호출하라, 이때 Array.prototype.slice의 this는 arguments 객체로 바인딩하라.
자바스크립트는 프로토타입기반의 객체지향 프로그래밍을 지원
자바스크립트의 모든 객체는 자신의 부모인 프로토타입 객체를 가리키는 참조 링크 형태로 숨겨진 프로퍼티가 있다.
implicit prototype link : [[Prototype]]
프로토타입 체이닝
자바스크립트에서 특정 객체의 프로퍼티나 메서드에 접근하려고 할 때,
해당 객체에 접근하려는 프로퍼티 또는 메서드가 없다면
[[Prototype]]링크를 따라 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티를 차례대로 검색하는 것
객체 리터럴 방식과 약간 다른 프로토타입 체이닝이 이뤄지지만 아래의 기본 원칙은 지킨다.
자바스크립트에서 모든 객체는 자신을 생성한 생성자함수의 prototype 프로퍼티가 가리키는 객체를
자신의 프로토타입객체(부모객체)로 취급한다.
Object.prototype이 프로토타입 체이닝의 종점이다.
자바스크립트는 Object.prtototype, String,prototype 등과 같이
표준 빌트인 프로토타입 객체에도 사용자가 직접 정의한 메서드들을 추가하는 것을 허용한다.
공용적으로 사용하는 메서드의 경우 prototype에 선언하긔
angular에서 pipe의 성격으로 사용하는 함수들을 prototype에 넣어도 됨
프로토타입 객체 역시 자바스크립트 객체이므로, 일반 객체처럼 동적으로 프로퍼티를 추가/삭제하는 것이 가능하다.
메서드 호출패턴에서의 this는 그 메서드를 호출한 객체에 바인딩된다.
프로토타입 객체도 이 this바인딩 규칙이 적용된다.
📒 인사이드 자바스크립트 중 메모해야할 부분만 적었습니다.
1 | // 함수 선언문 |
1 | // 함수 표현식 |
()
를 붙여서 기술한다.함수 이름이 포함된 함수 표현식
1 | // add 변수가 sum 함수를 참조한다. |
함수를 재귀적으로 호출하거나, 디버거에서 함수를 구분할 때 사용
함수 선언문은 자바스크립트 엔진에 의해서 함수 표현식 형태로 변경되기 때문에 호출가능하다.
1 | function add(x,y){ |
함수도 일반 객체처럼 값으로 취급된다. (일급객체)
1 | var add = new Function('x','y','return x + y'); |
함수 호이스팅은 함수를 사용하기 전에 반드시 선언해야 한다는 규칙을 무시하므로, 코드의 구조를 엉성하게 만들 수 있다.
함수 표현식을 권장한다.
이를 자세히 알기 위해서는 실행컨택스트를 이해하면 된다.
자바스크립트의 변수 생성과 초기화의 작업이 분리되서 진행되기 때문이다.
함수 자체가 일반 객체처럼 프로퍼티들을 가질 수 있다.
1 | function add(x,y){ |
자바스크립트에서 함수는 일급객체이다.
이 특징때문에 함수형 프로그래밍이 가능하다.
자바스크립트의 함수를 제대로 이해하려면
함수가 일급 객체이며
이는 곧 함수가 일반 객체처럼 값으로 취급된다는 것을 이해해야한다.
1 | const foo = 100; |
클로저
함수 객체만의 표준 프로퍼티가 정의되어 있다.
length, prototype 이외의 프로퍼티는 ECMA 표준이 아니다.
__proto__
__proto__
대박 처음에 프로토타입 공부할 때 한참 헷갈렸던 부분
ECMAScript 명세서에서는 예외적으로 Function.prototype 함수 객체의 부모는 Object.prototype 객체라고 설명하고 있다.
Function.prototype 객체가 표준으로 가지는 프로퍼티나 메서드.
constructor
프로퍼티toString()
메서드 (Object.prototype에도 존재한다.)apply(thisArg, argArray)
메서드call(thisArg, [, arg1 [,arg2,]])
메서드bind(thisArg, [, arg1 [,arg2,]])
메서드인자의 개수를 나타내고 있다.
모든 함수는 객체로서 prototype 프로퍼티를 갖고 있다.
__proto__
와 혼동되면 안된다.__proto__
는 부모 역할을 하는 프로토타입 객체를 가리킨다.1 | function Person(name, gender) { |
함수 표현식에서 함수이름은 꼭 붙이지 않아도 되는 선택사항이다. (익명함수)
익명함수의 대표적인 용도가 콜백함수.
콜백함수는 코드를 통해 명시적으로 호출하는 함수가 아니라,
개발자는 단지 함수를 등록하기만 하고,
어떤 이벤트가 발생하거나 특정 시점에 도달했을 때
시스템에서 호출되는 함수를 말한다.
또한, 특정 함수의 인자로 넘겨서, 코드 내부에서 호출되는 함수 또한 콜백함수가 될 수 있다.
= 함수를 정의함과 동시에 바로 실행하는 함수
1 | (function(name){ |
초기화 코드
자바스크립트 라이브러리나 프레임워크 소스들 (like Jquery)
1 | (fucntion(window, undefined){ |
함수 코드 내부에서 함수 정의
공용으로 쓰이지 않고 정말 내부에서만 쓰일때
예_ html을 만드는 함수에서 받은 data에서 특정 추가작업을 해야하고, 공용함수로 쓰이지 않을 경우
내부함수에서는 자신을 둘러싼 부모 함수의 변수에 접근이 가능하다.
내부 함수는 일반적으로 자신이 정의된 부모함수내부에서만 호출 가능하다.
1 | function parent(){ |
1 | function parent(){ |
📒 인사이드 자바스크립트 중 메모해야할 부분만 적었습니다.
목차
for in
문 객체 프로퍼티 출럭delete
대괄호 표기법
마침표 표기법
1 | var foo = { |
대괄호 표기법만 사용해야하는 경우
for in
문 객체 프로퍼티 출럭for in 문을 사용하면 객체에 포함된 모든 프로퍼티에 대해 루프를 수행할 수 있다.
키 값을 출력할 수 있음
1 | const foo = { |
delete
1 | delete foo.major |
자바스크립트에서 배열 역시 객체인데, 배열과 일반객체와는 약간 차이가 있다.
1 | //colorsArray 배열 |
1 | const arr = ['zero', 'one', 'two']; |
신기하다!!
일반 객체에 length라는 프로퍼티가 있으면 어떻게 될까?
자바스크립트에서는 length라는 프로퍼티를 갖고 있는 객체를 유사배열객체라고 한다.
apply()
메서드를 사용하여 객체지만 표준 배열 메서드를 활용하는 것이 가능하다.1 | const arr = ['bar']; |
[📕 퀵스타트 Rxjs]를 보고 메모한 부분을 정리했습니다.
데이터를 추출하고 변환하는 작업을 빈번하게 하고 있다.
반복문, 분기문, 변수는 우리 코드를 복잡하게 만든다.
반복문 : 가독성을 떨어뜨림
분기문 : 확인해야 할 프로그램의 흐름을 여러 개로 만듦
변수 : 누군가에 의해 변경 될 수 있다.
=> 오류 발생 빈도를 높인다.
로직의 복잡성을 줄이는 방법 : 기능을 쪼개기 (관심사 분리)
기능을 추상화
변수의 사용은 오류를 발생시킬 수 잇는 확률을 높인다는 것.
함수형 프로그래밍의 특성을 가진 자바스크립트 함수를 이용하면
실제 로직과 상관없는 반복분, 분기문을 분리할 수 있다.
자바스크립트는 일급객체!
- 함수를 변수 혹은 데이터 구조에 저장할 수 있다.
- 파라미터로 함수를 전달 할 수 있다.
- 반환값으로 사용할 수 있다.
고차함수 Higher-order function
1 | function process(people){ |
1 | // 고차 함수를 이용하여 개선 |
개선된 process에서는 반복문, 분기문, 변수가 존재하지 않는다.
핵심로직은 분리되었고
코드의 흐름은 단일화 되었다.
변수를 사용하지 않음으로써 오류 발생 빈도도 크게 줄었다.
http://reactivex.io/rxjs/manual/index.html
rxjs에서 제공하는 오퍼레이터를 이용하면 observable을 생성할 수도 있고,
전달된 데이터를 변환하거나 필요한 데이터만을 추출할 수도 있다.
ES5 Array의 고차함수들이 반환값으로 새로운 Array 객체를 반환하여 각각에 영향을 미치지 않도록 하는 것과 같이,
rxjs의 오퍼레이터는 항상 새로운 observable을 반환함으로써 array의 고차 함수와 같이 불변 객체(immutable object)를 반환한다.
차이점 : Array의 리턴 객체는 새로운 레퍼런스 객체지만,observable과 달리 객체 자체가 불변객체는 아니다.
1 | var arr = [1,2,3]; |
1 | map = function(transformationFn){ |
1 | ajax$.pipe( |
[📕 퀵스타트 Rxjs]를 보고 메모한 부분을 정리했습니다.
상태 전파. state propagation
각각의 상태 머신들은 각자의 상태를 가지고 있고, 상태 머신들은 각자의 역할에 따라 서로 유기적으로 연결되어 있다.
모듈간의 의존성.
예_ 사용자정보(상태)를 System 클래스가 check()함수에서 사용하고 있는 예제
pull 시나리오
push 시나리오
push 방식으로 구성된 옵서버패턴은
subject의 상태가 변경되었을 경우
관찰하는 observer에게 자동으로 알려준다.(subscribe)
subject와 observer가 1:n
의 상황에서는 더욱 효과적이다.
다수의 observer를 subject에 등록하기만 하면
subject의 변경사항이 등록된 다수의 observer에게 자동으로 전달된다.
옵저버 패턴은 Observer.update만 존재하기 때문에 Subject에서는 옵저버 인터페이스에 대한 별도의 비용이 존재하지 않는다.
뉴스를 발행하는 신문사와 이를 구독하는 고객
뉴스를 발행하는 신문사 = subject
고객 = observer
신문사는 고객을 등록하고 신문이 발행될 때 각각의 고객에게 신문이 발행되었다고 알려준다.(notify)
신문이 발행되면
어떤 고객은 뉴스를 스크랩하거나,
어떤 고객은 뉴스를 읽기 시작한다.
rxjs도 상태 변화에 대한 문제를 옵저버 패턴을 기반으로 해결하려고 하였다.
옵저버 패턴에는 종료 flag가 없기 때문에 별도의 규칙을 정해야한다.
rxjs에서는 complete
옵저버 패턴은 에러 발생여부를 observer들에게 전달할 방법은 딱히 없다.
rxjs에서는 error
코드의 복잡도를 증가시키는 경우가 많다.
rxjs에서는 옵저버블은 오직 read-only
rxjs에서 전달되는 데이터는 모두 observable형태로 변환된다.
observable은 구독과정(subscribe)후부터 데이터를 전달받기 시작한다.
rxjs의 observable
1 | const {fromEvent} = rxjs; |
observer pattern
1 | let newsPaper = new Subject(); |
subject와 observer
상태가 변경되는 아이 : subject, observable
rxjs의 observable ≒ 옵서버 패턴의 Subject
변경된 상태를 알아야 하는 아이 : observer
옵서버 패턴의 observer는 add라는 메소드를 통해 subject에게 전달된다.
rxjs의 observer는 함수와 객체 둘 다 가능하며 subscribe라는 메소드를 통해 subject에게 전달된다.
rxjs가 기존 옵저버 패턴의 아쉬웠던 점을 개선하고자 했기 때문이다.
Rxjs에는 observable도 있고 subject도 있다.
rxjs의 subject는 기능적으로 정확히 옵저버패턴의 subject와 일치한다.
rxjs의 subject는 다수의 observer에게 공통의 데이터를 전달하고, update와 같은 메소드가 존재하여 데이터 변경도 가능하다.
rxjs의 observable은 기능적으로 옵저버 패턴의 subject와는 엄격히 다르다.
observable은 하나의 observer에게 독립적인 데이터를 전달한다.
update => next
데이터의 연속적인 변화를 observer에서 표현할 수 있도록 기존 update메서드를 next로 바꾸었다.
개인적으로는 update가 더 명시적이다 ..ㅜ
종료시점, 에러시점
옵저버 패턴에는 없던 종료시점, 에러시점을 개선,
종료는 compleate
에러는 error
observable.subscribe는 객체, 함수 모든 형태로 전달 받을 수는 있다.
subscribe는 특별한 경우를 제외하고는 가급적 함수 형태를 사용한다.
객체는 상태를 가질 수 없기 때문이다.
객체가 상태를 가진다는 의미 => 또다른 상태 머신이 될 수 있다는 의미.
반면 함수는 상태가 존재하지 않는 기능만을 담당하기 때문에 상태에 관한 문제에서는 보다 자유롭다.
observable은 subscribe를 통해 데이터를 전달할 대상에게 데이터를 전달할 수는 있지만,
반대로 observer에게 데이터를 전달받을 수 없다.
데이터가 발생하게 되면 옵저버에게 자동으로 빠르게 변경된 데이터를 전달한다.
이를 보고 리액티브하다고 이야기한다.
데이터 흐름과 상태 변화 전파에 중점을 둔 프로그램 패러다임이다.
사용되는 프로그래밍 언어에서
데이터 흐름을 쉽게 표현할 수 있어야 하며
기본 실행 모델이 변경 사항을 데이터 흐름을 통해 자동으로 전파한다는 것을 의미한다.
예: 엑셀
이런 고민의 해결책이 옵저버 패턴이고,
rxjs는 이런 옵저버 패턴을 개선하여 애플리케이션에서 발생하는 모든 데이터를 리액티브하게 전달할 수 있게 해준다.
[📕 퀵스타트 Rxjs]를 보고 메모한 부분을 정리했습니다.
게시판을 예로 생각.
목록화면 : 서버에 저장된 글을 보여주는
상세화면 : 게시글의 내용을 보여주는 상세화면
<textarea>
를 통해 사용자 입력을 받는다.<textarea>
에 있는 데이터를 json객체로 저장 후, 서버로 ajax요청을 한다.: 작업이 들어온 순서에 맞게 차근차근 하나씩 진행되는 것을 의미한다.
: 작업이 들어온 순서에 상관없이 산발적으로 작업이 진행된다.
입력데이터에 대한 구조적 문제를 개선하고자 하였다.
rxjs는 동기와 비동기의 차이점을 시간이라는 개념을 도입함으로써 해결하려고 했다.
동기와 비동기는 시간의 축으로 봤을 때는 같은 형태이다.
=> 시간을 인덱스로 둔 컬렉션으로 생각할 수 있다.
=> Rxjs는 이를 스트림이라고 표현한다.
=> Rxjs는 이런 스트림($)을 표현하는 Observable 클래스를 제공한다.
시간을 인덱스로 둔 컬렉션을 추상화한 클래스이다.
동기나 비동기 동작 방식으로 전달된 데이터를 하나의 컬렉션으로 바라볼 수 있게 해준다.
개발자는 데이터가 어떤 형태로 전달되는지에 대해 더이상 고민할 필요가 없어진다.
Observable을 통해 데이터를 전달받기만 하면된다.
동기던 비동기던 옵저버블로 데이터를 받긔
rxjs는 observable을 만들기 위해 rxjs 네임스페이스에 다양한 함수를 제공한다.(오퍼레이터)
이벤트를 observable로 만들때 fromEvent
를 사용한다.
단일데이터를 연속으로 전달하는 경우는 of
Observable 객체의 변수명은 관용적으로 접미사로 $를 붙인다.
Observable 객체는 스트림(stream)이다. 따라서 Stream을 뜻하는 S와 유사한 $를 Stream의 약어로 사용한다.
[프로그래밍의 정석]을 보고 메모한 부분을 정리했습니다.
함수의 경우 관심사 분리를 목표로 간결하게 유지한다.
단순함을 프로그래밍의 나침반으로 삼자.
아래 상황을 경계하자.
케바케일듯
지금 작성하는 코드가 정말로 필요한지를 항상 자문자답해야한다.
어떤 상황을 설명하는 데 필요 이상으로 많은 전제를 가정해서는 안된다는 사고방식.
= 뭔가에 관해 여러 가지 설명이 가능하다면 가장 단순한 방식이 옳다.
코드를 추상화함으로써 중복을 제거하자.
코드 로직을 추상화하려면
처리하는 코드를 묶고 이름을 붙여 함수화, 모듈화한다.
코드 중복을 제거하는 것을 목적 중 하나로 삼고 있다.
구조화 프로그래밍
DRY가 되어 있지 않은 코드에 대해 비꼬는 표현이다.
한번만, 단 한번만
DRY와 유사한 의미
시간이 지날수록 이렇게 사용하지도 않는 코드가 있는 것인지 영문을 알 수 없다. 오히려 방해물이 된다.
우선 사용할 수 있는 데 가치를 주자.
범용성보다는 단순성이라는 가치에 기준을 두고 고른다.
단순한 방식이 사실 범용성이 더 높을 때가 많다.
Program Intently and Expressively
의도를 표현해서 프로그래밍하라
블로그에 글을 쓰듯이 명확한 의도
사람이 읽기 위한 것이기 때문
코드는 소프트웨어 동작을 정확하고 완벽하게 알기 위한 유일한 실마리
코드와 가장 밀접하지만, 실시간으로 코드와 동기화되지 않는다.
결국 코드가 유일한 실마리
읽기 쉬움을 중시하자.
작성효율보다는 읽는 효율이 우선시된다.!!읽기 쉽다면 나중에 실행 효율을 높이기는 간단하다.
다른 사람이 내 코드를 볼 때 이해가 잘 되도록 노력하자.
읽기 쉽고
오류가 없으며
품질이 좋은 코드와
테스트를 작성하려면 시간이 걸린다.
이는 단기적으로 손실로 보이지만, 두더지 잡기식 개발이 되지 않으므로
장기적으로 반드시 이익을 가져다 준다.
주석으로 설명하지 않아도 되는 이해하기 쉬운 코드를 지향하면서,
표현할 수 없는 부분에는 주석을 활용하는 식으로
균형잡힌 코드를 작성하도록 하자.
literate programming
코드 자체를 문서화하는 기법
문서를 기술하기 위한 언어가 프로그래밍 언어와 결함되어 있다.
코드는 곧 문서이며, 문서는 곧 코드다.
Single Level of Abstraction Principle :: 추상화 수준의 통일
고수준 추상화 개념과 저수준 추상화 개념을 분리해야한다.
상하 2계층이 아니라 기능의 복잡도에 따라 여러 계층으로 분리한다.
각 계층에서는 추상화 수준을 일치시킨다.
1 | function 고수준() { //수준 1의 목차 |
함수를 구조화하자.
함수를 구조화하면 각 함수는 자신보다 한 단계 낮은 수준의 함수를 호출하는 처리가 중심이 된다.
다른 함수를 호출하는 코드로 구성된 함수 : 복합함수 (composed method)
복합함수
함수 뿐만 아니라 모듈 등에도 적용된다.
글을 쓸때는
내용을 쓰는 것과 내용을 이해하기 쉽게 전하기 위한 구성을 생각하는 것을 별개의 작업으로 본다.
Open-Closed Principle : 개방-폐쇠의 원칙
코드는 확장에 대해서 열려 있고
수정에 대해서 닫혀 있는
2가지 속성을 동시게 충족하도록 설계한다.
변경에 대해 유연하게 대응할 수 있는 유연한 설계가 요구된다.
코드의 모든 부분에 OCP를 적용하는 것은 과한 방식이다.
코드의 단순함을 우지할 수 없다.
변경내용을 지나치게 예측하지 말아야 한다.
실제 변경이 발생하기를 기다리는 전략.
첫번째 변경을 감수하고, 두번째부터 OCP를 적용한다.
기본적으로 예측 가능한 부분에는 확장성 있게 작업한다.
대표적인 기술 : 객체지향의 다향성
대표적인 디자인 패턴
참고링크
객체지향의 다향성 : http://webclub.tistory.com/406
strategy pattern : http://hyeonstorage.tistory.com/146
[프로그래밍의 정석]를 보고 메모한 부분을 정리했습니다.
1.1 프로그래밍에 은제탄환은 없다.
1.2 코드는 설계서다
1.3 코드는 반드시 변경된다.
소프트웨어 개발의 역사는 복잡함과 투쟁의 역사.
설계
설계서
공정(제조)
설계란 창조적이며 기예가 필요한 행위다.
(설계 = 기본설계 + 상세설계 + 프로그래밍 + 테스트 + 디버깅)
신입에게 맡길 첫 업무가 아니라 고도로 숙련된 프로그래머의 업무여야 한다.
[퀵스타트 Rxjs]를 보고 메모한 부분을 정리했습니다.
대부분 처음 개발을 시작할 때는 요구사항을 어떻게 프로그래밍할 것인지를 고민하게 된다.
즉, 구현 자체에만 초점을 맞추게 된다. 물론, 이는 개발에서 무엇보다 중요한 문제이다. 하지만, 시간이 지나 초급 개발자 딱지를 떼고 경험이 쌓이기 시작하면 구현보다는 소프트웨어를 얼마나 효과적으로 유지보수할 수 있는지? 또는 얼마나 많은 문제점을 설계나 테스트 코드를 통해 사전에 해결할 수 있을지를 고민하게 된다.
그래서 우리는 자연스레 기존 문제들을 해결하기 위해 고심했던 라이브러리나, 디자인 패턴들을 하나둘씩 적용하게 되고,
결국에는 이런 고민들이 녹아들어 간 프레임워크에 관심을 갖게 된다.
…
결과물(프레임워크)을 잘 사용하는 것도 중요하지만 그 기술의 결과물이 어떤 고민의 산물인지 아는 것이 더 중요하다.
주어진 시간의 상태(state)가 존재하고,
어떤 한 사건(input)에 의해
다른 상태 (state)로 변할 수 있는
수학적 모델을 의미힌다.
웹 어플리케이션은 이런 기능들의 집합으로 구성되어있다.
크게 보면 웹 어플리케이션도 하나의 큰 상태 머신인 셈.
웹 어플리케이션을 하나의 상태 머신으로 본다면
정확한 입력과 로직으로 상태를 관리하는 방법이 중요하다.
=> 이에 따라 오류의 발생 여부가 결정된다.
∴ 각 구성요소의 상태를 어떻게 관리하느냐에 따라 안정적인 어플리케이션을 만들 수 있다.
서버로부터 전달받은 데이터를 입력값으로 사용하는 경우
상태 오류가 발생하는 이유는 상태 변화를 정확하게 전달하지 못하는 경우이다.
cf__1. redux의 옵저버 패턴
1 | function createStore(reducer, initialState) { |
목차
디지털 카메라에서 이용되는 이미지 파일 포맷이다.
이 데이터는 JPEG, TIFF 6.0과 RIFF, WAV 파일 포맷에서 이용되며사진에 대한 정보를 포함하는 메타데이터
를 추가한다.
Exif는 JPEG 2000, PNG나 GIF파일에서는 지원하지 않는다.
EXIF 메타데이터는 다음 정보를 포함한다.
교환 이미지 파일 형식은 위치 정보
를 기록하는 표준을 갖고 있다.
기존에는 GPS 수신기를 내장한 극소수의 카메라만이 사진이 찍힌 장소의 정보를 저장할 수 있었다.
니콘 D300이나 니콘 D90, 파인픽스 S5 Pro, (캐논 EOS 6D 는 내부 장착)는 카메라 플래시 연결부에 별도의 GPS 수신기를 장착하여 지리 정보를 기록할 수 있다. 기록된 GPS 데이터는 컴퓨터에서 다른 디지털 사진에도 추가될 수 있다.
그러나 최근에는 GPS 수신기를 장착하고 사진 촬영이 가능한 수많은 휴대폰과 태블릿PC 등이 있어
해당 기기로 사진 촬영을 할 경우 위치 정보를 같이 저장할 수 있는 옵션을 지원하여 위치 정보를 함께 기록하여 촬영하기 쉬워졌다.
Exif 데이터는 이미지 파일 자체에 끼워진다.
많은 그래픽 소프트웨어에서 Exif 데이터를 인식하고,
파일이 변경될 때에도 메타데이터를 보존한다.
단 구버전의 경우에는 해당되지 않는다.
많은 이미지 갤러리 프로그램 역시 Exif 데이터를 인식하고, 이미지 옆에 Exif 정보를 보여 준다.
Exif 메타데이터는
포토샵이나 라이트룸에서 사진을 import한 후 info를 확인하면 사진 정보를 바로 확인할 수 있는데, 이 사진이 갖고 있는 exif데이터로 확인하는 듯
전체 flow는 이렇습니다.
1 | 1. input file에서 image upload |
1 | ... |
번거로운 작업이기 때문에.. 아래 라이브러리를 사용합니다.
개인적으로는 load-image-orientation
가 좋습니다 :)
orientation값에 따른 회전 이외에도 crop기능도 있습니다.
1 | // load-image-orientation.js |
라이브러리 내부를 보시면, orientation 값에 따라 image를 회전하는 것을 볼 수 있습니다.
이미지 resizing 함수도 따로 작업했었는데, 이번 이슈를 통해서 찾은 load-image 라이브러리에 리사이징관련된 메서드들도 있는 것을 확인했습니다.
[읽기 좋은 코드가 좋은 코드다.]를 보고 메모할 부분을 정리했습니다.
서론
좋은 코드는 무슨 일이 일어나고 있는지를 빠르게 전달해준다.
사용하기에도 즐겁고, 자신에게도 더 좋은 코드를 만들어야 하겠다는 욕구를 불러일으키기도 한다.
엔지니어링은 커다란 문제를
작은 문제들로 쪼갠 다음,
각각의 문제에 대한 해결책을 구하고,
다시 하나의 해결책으로 맞추는 일련의 작업을 한다.
이러한 원리를 코드에 적용하면 코드가 더 튼튼해지며 가독성도 좋아진다.
주어진 함수나 코드 블록을 보고, 스스로에게 질문하라
“상위수준에서 본 이 코드의 목적은 무엇인가?”
코드의 모든 줄에 질문을 던져라
“이 코드는 직접적으로 목적을 위해서 존재하는가?
혹은 목적을 위해서 필요하긴 하지만 목적 자체와 직접적으로 상관없는 하위문제를 해결하는가?”
상당히 원래의 목적과 직접적으로 관련되지 않은 하위문제를 해결하는 코드 분량이 많으면,
이를 추출해서 별도의 함수로 만든다.
함수는 오직 한 가지 작업만 수행해야 한다.
예시 ) 투표** 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15vote_changed(old_vote, new_vote); // 각 투표는 '추천','반대' 혹은 ''이다.
var vote_changed = function(old_vote, new_vote){
var scroe = get_score();
if(new_vote !== old_vote){
if(new_vote == 'Up'){
score += (old_vote === 'Down'? 2 : 1);
} else if (new_vote == 'Down'){
score -= (old_vote === 'Up' ? 2 : 1);
} else if (new_vote === ''){
score += (old_vote === 'Up' ? -1 : 1);
}
}
set_score(score);
}
위 코드의 흐름
1 | var vote_value = function(vote){ |
[읽기 좋은 코드가 좋은 코드다.]를 보고 메모할 부분을 정리했습니다.
서론
좋은 코드는 무슨 일이 일어나고 있는지를 빠르게 전달해준다.
사용하기에도 즐겁고, 자신에게도 더 좋은 코드를 만들어야 하겠다는 욕구를 불러일으키기도 한다.
흐름제어 control flow 논리식 logical expression 변수 등에 대해서 알아보자.
코드가 코드를 읽는 사람에게 정신적 부담을 더 많이 부과할 수록,
버그는 좀처럼 눈에 보이지 않고,
코드 수정 작업은 더 어려워지고,
결국 그런 코드로 작업하는 일이 즐겁지 못하게 된다.
분기문과 점프문은 어려운 대상이며, 코드를 복잡하게 만드는 원인이다.
A > B
cf_ 요다표기법 (옛날에 쓰던.. NULL == obj
)
if(!debug)
가 아니라 if(debug)
를 선호하자.?:
를 이용하는 조건문 표현루프와 조건문을 비롯한 그외 분기문을 읽기 쉽게 만드는 방법을 살펴본 것이다.
하지만 자신의 프로그램에 존재하는 ‘흐름’을 상위수준에서 조망해볼 필요가 있다.
프로그램의 전체 실행 경로를 쉽게 따라갈 수 있게 만드는 게 궁극의 목표다.
코드의 표현이 커지면 커질수록 이해하기 더 여렵다. ⇒ 예시: 대왕오징어 식도주변의 도넛뇌
if (!(file_exists && !is_protected))
if (!file_exists && is_protected)
1 | bool Range:;OverlapsWith(Range other){ |
1 | bool Range:;OverlapsWith(Range other){ |
거대한 구문 나누기
반복되는 부분을 ⇒ 요약변수로 추출할 때 (DRY : Don’t Repeat Yourself)
표현을 단순화하는 다른 창의적인 방법들
변수를 엉터리로 사용하면 코드를 이해하기가 얼마나 어려워지는지 살펴본다.
1 | var remove_one = function (array, value_to_remove) { |
‘전역변수를 피하라’는 조언을 한번쯤 들었을 것이다.
사실 전역 변수 뿐만 아니라 모든 변수의 범위를 좁히는 일은 언제나 좋다.
많은 프로그래밍 언어는 모듈, 클래스, 함수, 블록 범위 같은 다양한 범위/접근 수준을 제공한다.
자바스크립트에서 프라이빗 변수 만들기
1 | submitted = false; |
submit_form()
만이 전역변수 submitted를 사용하는 유일한 함수처럼 보이지만,
확실히 알 수 없다.
⇒ 다른 자바스크립트 파일에서 이와는 다른 목적으로 submitted라는 이름이 붙은 전역 변수를 사용할 지도 모르는 일이다!⇒ submitted 변수를 클로저 내부에 집어 넣어서 이런 문제를 해결한다.
1 | var submit_form = (function(){ |
⇒ 프라이빗한 범위를 만드는 효과를 갖는다.
[읽기 좋은 코드가 좋은 코드다.]를 보고 메모한 부분을 정리했습니다.
서론
좋은 코드는 무슨 일이 일어나고 있는지를 빠르게 전달해준다.
사용하기에도 즐겁고,
자신에게도 더 좋은 코드를 만들어야 하겠다는 욕구를 불러일으키기도 한다.
⇒ 이런 수정은 코드를 리팩토링하거나 프로그램이 동작하는 방식을 바꾸지 않고 그 자리에서
곧바로 만들 수 있기 때문에 수정 반영이 쉽다.
⇒ 코드베이스를 흔드는 행위이므로 결과적으로 작성하는 모든 코드에 영향을 줄 수 있다.
변수, 함수, 혹은 클래스 명을 결정할 때
⇒ 이름에 정보를 담아내라
get
은 지나치게 보편적이다.
fetch
download
send 보다는
find 보다는
start 보다는
make 보다는
tmp, retval(: 반환된 값), foo 같은 이름은
내 머리로는 이름을 생각해낼수 없어요..
tmp
: 변수 목적 자체가 코드 몇 줄에서만 사용하는
임시저장소의 역할을 할 경우에는 사용해도 ok
루프반복자
i
, j
, iter
, it
인덱스나 루프 반복자로 사용된다.
배열이름과 + 인덱스를 합친 반복자로 사용하면 좋다.
1 | for(let i = 0; i < clubs.size(); i++) |
i, j, k보다는 ⇒ club_i
, members_i
, users_i
혹은 ci
, mi
, ui
tmp, it, retval 같은 보편적인 이름을 사용하려면,
꼭 그러게 해야하는 이유가 있어야 한다.
_ms
)변수가 시간의 양이나 바이트의 수와 같은 측정치를 담고 있다면,
⇒ 변수명에 단위를 포함시키는 게 도움이 된다.
1 | const start = (new Date()).getTime(); |
data_urlenc
)str
, evaluation 대신 eval
ToString()
ServeLoop()
< 다른 포맷팅 관습 >
jQuery 함수 호출시 jQuery의 결과를 저장하는 변수 앞에 $
붙이기
1 | var $all_images = $("img"); |
밑줄로 id안에는 단어를 구분하고, 대시로 클래스 안에 있는 단어를 구분 할 수 있다.
1 | <div id="middle_column" class="main-content"> ... |
본인이 지은 이름을
‘다른 사람들이 다른 의미로 해석할 수 있을까?’라는 질문을 던져보며
철저하게 확인해야 한다.
select()
나 exclude()
min
과 max
를 사용하라first
와 last
를 사용하라begind
과 end
를 사용하라is
/ has
/ can
/ should
get*()
: 가벼운접근자(lightweight accessors)로서 단순히 내부 멤버를 반환한다고 관행적으로 생각한다.좋은 소스 코드는 ‘눈을 편하게’ 해야한다.
선언문을 블록으로 구성하라
코드를 문단
으로 쪼개라
핸들러, 헬퍼함수
핸들러
이벤트에 응답해서 호출되는 함수를 이벤트 핸들러(이벤트 리스너)라고 합니다.
헬퍼함수
함수를 재사용할 수 있는 헬퍼함수
감독의 설명을 포함하라
중요한 통찰은 기록하자.
1 | // 이 클래스는 점점 엉망이 되어가고 있다. 어쩌면 'ResourceNode' |
코드에 있는 결함을 설명하라
1 | // TODO: 더 빠른 알고리즘을 사용하라. |
TODO:
아직 하지 않은 일FIXME:
오작동을 일으킨다고 알려진 코드HACK:
아름답지 않은 해결책XXX:
위험! 여기 큰 문제가 있다TextMate:
ESC상수에 대한 설명
팀에 새롭게 합류한 사람들은 ‘큰 그림’을 이해하는 데 어려움을 겪는다. 클래스들이 어떻게 상호작용하고, 전체 시스템에서 데이터가 어떻게 흘러 다니고, 출발점이 어디인지 등을 파악해야한다.
1 | def GenerateUserReport(): |
https://d2.naver.com/helloworld/59361 를 읽고 정리했습니다.
< DOM과 CSSOM을 결함 = 렌더링트리 >
head
요소와 같은 비시각적 DOM 요소는 렌더 트리에 추가되지 않는다.none
값이 할당된 요소는 트리에 나타나지 않는다.<div>
에 규칙을 적용한다는 뜻이다.<div>
요소를 확인하려면 트리로부터 임의의 줄기를 선택하고 탐색하는 과정에서 규칙에 맞지 않는 줄기를 선택했다면 또 다른 줄기를 선택해야 한다.https://d2.naver.com/helloworld/59361 를 읽고 정리했습니다.
어휘 분석
과 구문 분석
으로 구분할 수 있다.자료를 유효한 토큰으로 분해하는 어휘 분석기(lexical analysis)가 있고,
언어 구문 규칙에 따라 문서 구조를 분석함으로써 파싱 트리를 생성하는 파서가 있다.
1 | INTEGER : 0|[1-9][0-9]* |
1 | expression := term operation term |
문법이 문맥자유문법(= 완전히 BNF 로 표현 가능한 문법)이라면,
언어는 정규 파서로 파싱할 수 있다.
웹킷
HTML 파서는 HTML 마크업을 파싱 트리로 변환한다.
너그럽다.
HTML 은 일반적인 하향식 혹은 상향식 파서로 파싱이 안된다.
document.write
을 포함하고 있는 스크립트 태그는 토큰을 추가할 수 있기 때문에 실제로는 입력 과정에서 파싱이 수정된다.일반적인 파싱 기술을 사용할 수 없기 때문에 브라우저는 HTML 파싱을 위해 별도의 파서를 생성한다.
TL;DR
알고리즘은 토큰화와 트리구축 이렇게 2 단계로 되어 있다.
(HTML 파싱 과정그림)
아래가 더 세분화된 과정
예시 >
1 | <html> |
0.초기상태 : 자료 상태
<html>
<body>
<
문자를 만나면 변함>
를 만날 때까지 유지한다.>
문자에 도달하면 현재 토큰이 발행된다.Hello world
<
문자를 만날 때까지 진행</body>
</html>
/
문자는 종료 태그 토큰 생성>
문자에 도달하면 현재 토큰이 발행된다.예시 >
1 | <html> |
HTML 페이지에서 “유효하지 않은 구문”이라는 오류는 볼 수 없는데,
이는 브라우저가 모든 오류 구문을 교정하기 때문이다.
파서는 토큰화된 입력 값을 파싱하여 문서를 만들고 문서 트리를 생성한다.
때문에 파서는 적어도 다음과 같은 오류를 처리해야한다.
< 웹킷의 오류 처리하는 예 >
<br>
대신 </br>
<br>
대신 </br>
을 사용한다.<br>
으로 간주한다.어긋난 표는 표 안에 또 다른 표가 th 또는 td 셀 내부에 있지 않은 것을 의미한다.
웹킷은 표의 중첩을 분해하여 형제 요소가 되도록 처리한다.
폼 안에 또 다른 폼을 넣은 경우 안쪽의 폼은 무시된다.
최대 20 개의 중첩만 허용하고 나머지는 무시한다.
깨진 html 을 지원한다. 일부 바보 같은 페이지는 문서가 끝나기 전에 body 를 닫아버리기 때문에 브라우저는 body 태그를 닫지 않는다. 대신 종료를 위해 end()를 호출한다.
DOM 트리는 문서 마크업의 속성 및 관계를 포함하지만 요소가 렌더링될 때 어떻게 표시될지에 대해서는 알려주지 않습니다.
이것은 CSSOM 의 역할.
<script>
태그를 만나서 실행되는 동안 문서의 파싱은 중단된다. (그래서 바디 전에 넣음)https://d2.naver.com/helloworld/59361 를 읽고 정리했습니다.
사용자 인터페이스
브라우저 엔진
렌더링 엔진
통신
UI 백엔드
자바스크립트 해석기
자료 저장소
HTML
및 XML
문서와 이미지
를 표시할 수 있다.XML
XML이란 문자 기반의 마크업 언어, HTML처럼 데이터를 보여주는 목적이 아닌, 데이터를 저장하고 전달할 목적으로 만들어졌음. XML태그는 HTML태그처럼 미리 정의되어 있지 안혹, 사용자가 직접 정의할 수 있다.
파이어복스, 크롬, 사파리는 두 종류의 렌더링 엔진으로 제작되어있다.
렌더링 엔진은
궁금
URL
URI
오늘은 이미지 용량을 줄이는, (리사이징이 더 맞는 말이겠죠.) 방법에 대해서 알아보려고 합니다. 로컬에서 이미지 파일을 올리는 것부터 시작하죠. 이를 위해서는 HTML5관련 API 중 하나인 파일 API를 이용하고, 이미지 리사이징을 위해서 캔버스를 이용할 것입니다. 파일API를 다뤄보고 Blob에 대해서도 알아보죠..(Blob의 더 자세한 내용을 위해 포스팅을 따로 해야 할 것 같습니다.) ( + 제이커리 사용했습니다.)
보통 웹에서 글을 게시할 때 이미지를 첨부해야 하는 기능이 있죠. 이미지 업로드시 용량 축소가 기본적으로 들어가야 하고, 이는 프론트단에서 작업해주는게 보통입니다! 유저들이 보통 올리는 이미지는 스마트폰 사진이 일반적일 텐데, 요즘 스마트폰 카메라 성능이 좋아지면서 많게는 개당 8MB까지 나오는 경우도 있죠. 서버단에서 리사이징할 경우 비용이 아깝게 들기 때문에.. 클라이언트에서 이를 작업합니다. 전체 플로우는 이렇습니다.
input의 type=file
를 이용해서 이미지 파일에 접근, file 객체들을 files 컬렉션에 담습니다. 각 객체가 파일 하나를 나타냅니다.(Blob)
파일 객체에는 여러가지 읽기 전용 프로퍼티가 존재합니다.
파일 API는 FileReader 타입을 통해 파일 데이터를 읽을 수 있습니다.
FileReader 타입은 비동기적으로 파일을 읽는 메커니즘입니다. 서버에서 파일을 읽는 것이 아닌, 파일 시스템에서 파일을 읽는 것이라고 이해하자.
FileReader 타입에는 파일 데이터를 읽는 여러 가지 메서드가 존재합니다.
읽는 과정은 비동기적이므로 FileReader는 progress, error, load 이벤트를 일으킵니다.
1
: 파일을 찾을 수 없음2
: 보안 에러3
: 읽기 거부4
: 파일을 읽을 수 없음5
: 인코딩 에러load 이후에는 readAsDataURL 메서드를 통해 result 프로퍼티에 데이터 URI가 저장되도록 해야 합니다.
1 | <!-- html 🚀🚀 --> |
1 | const load_image = e => { |
이미지는 용량에 따라 로드 속도가 다릅니다. 웹은 이미지에 대해서 비동기적으로 동작하는데 완전히 로드될 때까지 기다리지 않고 웹 페이지를 일단 표시한 후 이미지는 따로 읽습니다. 때문에 이미지를 읽은 직후 바로 출력하면 제대로 동작하지 않습니다. filereader를 통해서 파일을 읽은 이후 이미지 리사이징을 하려고 했지만, 이미지가 아직 로드되지 않았는데 리사이징하면 당연히 canvas의 이미지는 존재하지 않겠죠?
image가 읽혀진 후에 리사이징이 이루어지도록 하기 위해서 filereader와 마찬가지로 load 콜백 내부에 리사이징 함수를 넣어둘 것입니다.
load 이벤트를 사용하기 위해 Image 인스턴스를 생성합니다.
reader.onload의 콜백 내부에 image 인스턴스를 생성하고, image가 읽을 수 있는 형태가 되면 image.onload가 발생되도록 합니다. (자세한건 코드..!)
1 | const load_image = e => { |
resize_image 함수에 인자로 앞서 생성한 image 요소를 넘겨받게 했습니다.
리사이징을 위해서 캔버스 엘리먼트를 생성한 후, 캔버스에 2d 컨텍스트의 image를 리사이징된 폭과 높이로 그릴 것입니다.
1 | const resize_image = image => { |
Data URIs는 네 가지 파트로 구성됩니다data:[<mediatype>][;base64],<data>
Base64
바이너리 데이터를 문자 코드에 영향을 받지 않는 공통 ASCII 문자로 표현하기 위해 만들어진 인코딩이다. 네이버 지식iN 등의 URL에서 자주 볼 수 있는 형태의 바로 그것.
ASCII 문자 하나가 64진법의 숫자 하나를 의미하기 때문에 BASE64라는 이름을 가졌다.
Blob
Blob은 일련의 데이터를 처리하거나 간접 참조하는 객체다. Blob이란 이름은 SQL 데이터베이스에서 유래하였으며 ‘대형 이진 객체(Binary Large Object)’를 의미한다. 자바스크립트에서 Blob은 흔히 이진 데이터를 나타내며 해당 데이터의 크기가 매우 클 수 있지만, 두 가지 특징 모두 강제된 사항은 아니다. 즉, 작은 텍스트 파일의 내용도 Blob으로 나타낼 수 있다. Blob은 대개 바이트의 크기를 알아내거나, 해당 MIME 타입이 무엇인지 요청하며, 데이터를 작은 Blob으로 잘게 나누는 등의 작업에 사용된다. 즉, 데이터 자체라기보다는 데이터를 간접적으로 접근하기 위한 객체인 것이다.
Blob.size
Blob 객체에 포함된 데이터의 바이트 단위의 사이즈를 의미한다.
Blob.type
Blob에 포함된 데이터의 MIME 타입을 의미한다. 만약 unknown으로 나올 경우, 이 문자열은 비어있는 것이다.
1 | const dataURLToBlob = dataURL => { |
ajax로 보낼 경우 FormData 생성후 최종 생성한 Blob 객체를 추가하면 됩니다.
현재 작업 중인 프로젝트는 데스크탑 브라우저(여러 브라우저 대응) 뿐만아니라 모바일 기기 대응도 진행해야한다. 너무도 당연히 대응해야하지만!! 기기의 종류들의 크기가 다양해짐에 따라서 미디어쿼리를 적절히 사용해야할 필요가 생겼다.(아이폰X나 갤럭시S9같은.. 스크린이 긴 단말기ㅜ) 게다가 네이티브앱에서 웹뷰를 이용하는 일이 빈번했기 때문에 더더욱..
@media
CSS3의 @media 쿼리를 이용해서 screen의 크기에 따라서 레이아웃 구성을 다르게하는 방법을 구현할 수 있다. 반응형 웹에서는 다른 특별한 설정 없이 max-width같은 media features를 추가하여 브라우저의 width값마다 스타일을 조정할 수 있다.
1 | /*syntax*/ |
all
: 모든 디바이스에 적용print
: printer에 사용screen
: 컴퓨터 스크린, 태블릿, 스마트폰 등에 쓰임speech
: 스크린 리더기에 사용, 스크린 내용을 읽어주는 미디어 일때(정말 많군요! 👀)
height, width
: 둘 다 해당, 둘 다 미디어에 따라 다른 값들이 검출 됨width : 320px
: 미디어가 320px일때max-width : 320px
: 320px 이하의 미디어 일 때min-width : 320px
: 320px 이상의 미디어 일 때device
: device의 물리적인 값들을 기준으로(해상도와 너비는 같지 않을 수 있다)device-width : 320px
: 기기의 너비가 320px일때max-device-width : 320px
: 320px 이하의 화면일 때min-device-width : 320px
: 320px 이상의 화면일 때orientation
:aspect-ratio
, min-aspect-ratio
, max-aspect-ratio
(화면비율) : width/height (가로 나누기 세로)aspect-ratio:1
: 화면 비율이 1:1인경우aspect-ratio:16/9
: 일반적인 화면 비율인 16:9를 의미합니다(1920*1080)device-aspect-ratio
, min-device-aspect-ratio
, max-device-aspect-ratio
: 단말기의 물리적인 화면 비율color
, min-color
, max-color
: 단말기에서 사용하는 최대 색상 비트 수에 대응(단위는 자연수)color:3
: 2³ = 8개의 색상 사용color-index
, min-color-index
, max-color-index
: 최대 색상 수에 대응monochrome
, min-monochrome
, max-monochrome
: 흑백만 사용하는 단말기에서의 픽셀당 비트수, 얼마나 자유롭게 표현되는지를 확인함resolution
, min-resolution
, max-resolution
: 단말기의 해상도grid
: 단말기가 grid방식인지 bitmap방식인지grid:1
⇒ 문자로만 표기되는 tty, 주로 터미널, 전화액정grid:0
⇒ 대부분의 컴퓨터와 스마트폰 웹 브라우저에 해당-webkit-min-device-pixel-ratio
: 단말기의 화소와 실제 화면의 pixel간의 비율사실 단말기에 따른 media query는 인터넷 서핑을 잘 하다보면 구할 수 있다.
(여긴 내가 좋아하는 정리 사이트)
나 또한 정리되어있는 자료에서 device width와 height, -webkit-min-device-pixel-ratio를 구할 수 있었다. 정리된 수치로 잘 사용하고 있었지만, 종종 서치하기 힘든 디바이스까지 대응해야할 경우도 생기곤 한다. 그리고 나에게도 그런 상황이 다가왔다!
내가 대응해야할 폰은 LG X400이라는 디바이스였다. 최근에 나온 기종이고, 내가 알 수 있는 정보는 아래 표밖에 없었다.
@media only screen and
(device-width: ?px
) and
(device-height: ?px
) and
(-webkit-device-pixel-ratio: ?
) {
위의 값들이 필요하다. 먼저 픽셀 비율부터 구해보자.
디바이스 픽셀 비율을 계산하는 데는 세 단계가 필요하다.
스펙에 따르면 28인치에서 이상적인 것은 인치 당 96 픽셀이다.(표준밀도는 96ppi) 그러나 스마트 폰이기때문에 사람들은 노트북을 들고 다니는 것보다 디바이스를 얼굴에 가깝게 들고있는다. 그 거리를 18 인치로 추정 해본다.
idealPixelDensity = (28/18) * 96 = 150 픽셀/인치 (대략)
devicePixelRatio = 294/150 = 1.96 => 반올림 => 2
현재 알 수 있었던 해상도는 표에서 1280*720 라고 알 수 있었다.
device의 너비와 height는 픽셀 비율을 해상도에서 나누면 된다.
1 | @media only screen and |
https://medium.com/@junghan_61455/css-media-query-5969b004bd7
https://www.html5rocks.com/en/mobile/high-dpi/
엥귤러 version2가 나왔을때, 엥귤러는 옵저버블
을 소개했다. 옵저버블은 엥귤러의 특정 기능은 아니고, ES7 릴리스에 포함될 비동기 데이터를 관리하기위한 새로운 표준이다. Angular는 이벤트 시스템과 HTTP 서비스에서 옵저버블을 광범위하게 사용한다. 옵저버블들을 이해하는 건 꽤 중요한 일일 수 있다. 그러므로 쉬운 방법으로 옵저버블을 설명하려고 왔다.
옵저버블은 시간이 지남에 따라 여러값을 가질 수 있는 지연 콜렉션이다.
옵저버블은 사실.. 꽤 쉽습니다.
지연 옵저버블을 뉴스 레터로 생각할 수 있다. 각 구독자(subscriber)마다 새로운 뉴스 레터가 만들어진다. 그 뉴스레터들은 구독자들에게만 보내고 다른 사람에게는 보내지 않는다.
뉴스 레터 구독을 계속 열어두면, 매번 새로운 뉴스 레터를 받게된다. 발신자(sender)는 받은 시간을 결정하지만 받은 편지함에 곧바로 올 때까지 기다려야한다.
여러분이 promise
의 세상에서 왔다면, 옵저버블과 프로미스간의 다른 중요한 차이점이 있는데, promise
은 항상 오직 하나의 값만을 반환한다는 점이다. 또 하나는 옵저버블의 구독을 취소 할 수 있다는 점이다. 뉴스 레터를 더 이상 원하지 않으면 구독을 취소하면된다. 프로미스를 사용하면 이점이 다른건데, 프로미스는 취소 할 수 없다. 프라미스가 당신에게 건네지면, 그 프라미스의 resolve가 이미 진행되고 있으며, 일반적으로 프라미스의 resolve가 실행되는 것을 막을 수 있는 권한이 없다.
observables를 사용할 때 이해해야 할 핵심 사항은 observables가 push한다는 것이다. (옵저버블은 push 시나리오를 따른다는 말) push와 pull은 데이터 생성자가 데이터 소비자와 커뮤니케이션하는 방법을 설명하는 두 가지 방식이다.
Pulling일 때 데이터 소비자는 데이터 생성자로부터 데이터를 가져 오는 시점을 결정한다. 생산자는 언제 데이터가 소비자에게 전달되는지를 알지 못한다.
모든 자바 스크립트 함수는 pull 시나리오를 사용한다. 함수는 데이터의 프로듀서이며 함수를 호출하는 코드는, 호출에서 하나의 반환 값을 “꺼내”(pull) 가져와 이를 소비한다.
Pushing일 때, 다른 방향으로 동작한다. 데이터 생성자 (뉴스 레터 생성자)는 소비자 (뉴스 레터 구독자)가 데이터를 가져 오는 시점을 결정합니다.
프로미스는 오늘날 자바 스크립트에서 사용하는 가장 일반적인 push 방법입니다. 프로미스(생산자) 전달자는 등록된 콜백(소비자)에게 resolve된 값을 전달하고, 프로미스는 함수와는 달리 콜백에 그 값이 “푸시 (push)”되는 시기를 정확하게 결정한다.
Observables는 JavaScript로 데이터를 푸시하는 새로운 방법이다. 옵저버블은 여러 값의 생산자로서 구독자에게 “푸시 (pushing)”한다.
Angular를 사용하기 시작하면 아마도 HTTP 요청을 설정할 때 옵저버블을 만날 것이다. http 요청부분부터 시작해봅시다.
1 |
|
우리는 이제 observable을 반환하는 fetchUsers 메서드를 사용하여 간단한 HttpClient를 만들었다. 어떤 종류의 리스트에 사용자를 표시하고 싶으므로 fetchUsers 메서드를 사용해서 해보자. 이 메소드는 옵저버블을 반환하기 때문에 우리는 그것을 구독해야 한다. Angular에서 우리는 두 가지 방식으로 Observable을 구독 할 수 있다 :
비동기 파이프를 사용하여 템플릿의 옵저버블을 구독하는 방법이 있다. 이로 인해 Angular는 컴포넌트의 생명주기 동안 구독을 처리한다. Angular는 자동으로 구독하고 구독취소한다. 비동기 파이프가 노출되야하므로 모듈에 “CommonModule”을 import하는 것을 잊지 마세요.
1 | import { Component } from "@angular/core" |
1 | <!-- We use the async pipe to automatically subscribe/unsubscribe to our observable --> |
달러 기호에 유의하세요. 옵저버블 변수 이름에 달러 기호를 사용하면 모범 사례로 간주된다. ($를 Stream의 약어로 쓴다.)이렇게하면 변수가 관찰 가능 여부를 쉽게 식별 할 수 있다.
우리는 실제 subscribe()
메소드를 사용하여 옵저버블을 구독한다. 데이터를 표시하기 전에 먼저 데이터에 뭔가 작업하기를 원한다면 편리할 수 있다. 단점은 구독을 직접 관리해야한다는 것다.
1 | import { Component } from "@angular/core" |
1 | <ul class="user__list" *ngIf="users.length"> |
템플릿 로직이 꽤 비슷하다는 것을 알 수 있듯이, 당신이 2번 방식으로 간다면 구성 요소 논리는 훨씬 더 복잡해 질 수 있다. 일반적으로 나는 방식1을 선택하는 것이 좋다. 가장 쉽고 구독을 수동으로 관리할 필요가 없다. 2번방법에서 구독을 사용하지 않는 동안 열어두면 메모리 누수가 발생하므로 좋지 않다.
Angular가 제공한 일반적인 옵저버블을 다루는 방법을 알았으므로 옵저버블을 어떻게 생성하는지 알고있는 것이 좋다. 가장 간단한 버전은 다음과 같다.
1 | import { Observable } from "rxjs/Observable" |
예제에서 볼 수 있듯이 observables는 새로운 Observable() 호출을 사용하여 만든 다음 observer에 가입하고 next()를 호출하여 실행하고 unsubscribe()를 호출하여 삭제한다.
observables를 만드는 것은 쉽다. 새로운 Observable()을 호출하고 옵저버를 나타내는 하나의 인수를 전달하면됩니다. 그러므로 저는 보통 그것을 “observer”라고 부릅니다.
옵저버블은 느긋하다는걸 기억하세요. 구독하지 않으면 아무 일도 일어나지 않을 것이다. 옵저버를 구독 할 때 subscribe()를 호출 할 때마다 옵저버블에 독립 설정이 실행된다는 사실을 알면 좋다. 구독 요청은 동일한 옵저버블에 대한 여러 구독자간에 공유되지 않는다.
observables 안의 코드는 observables의 실행을 나타낸다. 옵저버블을 만들 때 주어진 매개 변수(observer)에는 옵저버블의 구독자에게 데이터를 보낼 수있는 세 가지 함수가 있다.
next
: Number나 Array나 객체같은 여러 값을 subscribers에게 보낸다.error
: 자바스크립트 에러나 예외값을 보낸다.complete
: 어떤 값도 보내지 않는다.next
콜은 구독자에게 실제로 데이터를 전달할 때 가장 일반적이다. 옵저버블의 실행 중에는 observer.next()
의 무한 호출이있을 수 있지만 observer.error()
또는 observer.complete()
가 호출되면 실행이 중지되고 더 이상 데이터가 subscribers에게 전달되지 않는다.
옵저버블의실행은 무한한 시간 동안 실행될 수 있기 때문에, 실행을 막을 수있는 방법이 필요하다. 각 구독자마다 각 실행이 실행되기 때문에, 메모리와 컴퓨팅 성능이 낭비, 즉 더 이상 데이터가 필요없는 구독자는 구독을 멈추는 것이 중요하다.
옵저버블을 구독할 때, 진행중인 실행을 취소하면 구독이 반환된다. 실행을 취소하려면 unsubscribe()
를 호출하면 됨.
이 게시물을 통해 옵저버블이 실제로 어떻게 작동하는지 더 잘 이해할 수 있다. 다음 시간에 옵저버블에 대해서 더 많이 알기 위해 Rxjs의 강력함을 이해하고 이 제공하는 모든 헬퍼 함수를 이해하는 것이다.
]]>개인의 경험을 바탕으로 적은 글이기에 피드백은 언제나 댓글로 환영합니다. :)
목차
모듈 세팅
precommit, 커밋 전 옵션에 맞춰 재포맷 하는 hook 추가.
한 프로젝트에 프론트엔드 개발자가 여러 명일 경우 각자의 코드 스타일이 다르기 때문에 통일성을 위해 코드 포메터를 사용하면 코드를 깔끔하게 공유할 수 있다. 현재 진행 중인 angular 프로젝트에 react 프로젝트에서 사용했었던 Prettier라는 포매터를 사용하기로 결정했다. 초반에 어떻게 세팅할지만 논의하면 된다.
프리티어를 엥귤러 프로젝트에 적용하면서 겪었던 부분을 글로 공유하고자 한다.
참고로 에디터는 vscode
를 사용하고 있다.
angular cli 로 프로젝트를 생성하면 기본 구조가 세팅이 되는데, 엥귤러는 타입스크립트가 주력 언어이므로 타입스크립트를 위한 tslint.json 파일과 tsconfig.json 파일이 함께 세팅된다.tslint.json
파일은 tslint 가 사용하는 linting(구문 체크) 설정 파일이다. tslint 란 An extensible linter for the TypeScript language. 즉 타입스크립트 린터이다!
vscode 에서는 tslint 확장 프로그램을 설치하면 구문과 다른 곳을 빨간 줄로 표시해준다.tsconfig.json
파일은 타입스크립트 컴파일 옵션 설정 파일이다.
* 에디터에만 적용하기
프리티어 패키지
를 설치하는 방법과 플러그인
으로 세팅하는 방법이 있다.
개인적으로만 사용하거나 다른 개발자들이 모두 vscode 를 사용한다면 프리티어 플러그인을 설치하고 workspace settings 에만 설정해도 프리티어 세팅은 완료된다.Code > Preference > Settings > Workspace Settings
* 프로젝트에 적용하기
패키지 매니저로 프리티어를 설치한다.
1 | npm install prettier -D |
1 | { |
프리티어 옵션은 여러 가지 방식으로 세팅이 가능하다. rc 파일을 따로 만들어서 관리할 수도 있고, json 파일로 만들어서 관리를 할 수 있다. 우리 프로젝트에서는 package.json 파일에 포함시키기로 했다.
1 | ... |
vscode 세팅에서 "editor.formatOnSave": true
를 설정하면 저장하는 것과 동시에 프리티어가 적용된다.
프리티어에는 여러 가지 기본 옵션 값들이 있다. Prettier 자세한 내용은 홈페이지에서 확인 가능하다.
80
2
우리의 프로젝트에서는 아래의 옵션을 세팅했다.
1 | { |
printWidth 를 120 으로 하기도 하던데, 그건 취향껏! (에어비엔비는 80)
개발자마다 쓰는 에디터가 다르고, 각자가 각자 에디터에 세팅하는 부분에서 나올 수 있는 에러들을 방지하기 위해 프로젝트 자체에 세팅한 후 커밋 할 때마다 세팅하는 방법이 있다.
pre-commit 툴과 함께 사용하면 되는데 많이들 사용하는 husky
와 lint-staged
모듈을 사용하면 된다.
프리커밋 툴을 사용하면 git add 을 입력할 때 (husky
: hook) 린트 옵션에 맞춰서 재포맷을(lint-staged
: 재포맷) 시켜준다. 이때 옵션에 tslint 옵션도 재포맷 설정에 넣어줄 수 있으므로 git add 명령어 만으로 tslint 와 prettier 의 옵션들을 적용시킬 수 있다.
모듈 설치
1 | npm install --save-dev lint-staged husky |
tslint --fix -c tslint.json -p tsconfig.json
c 는 config 의 약어. tslint.json 파일의 옵션들을 확인하고 규칙에 맞춰서 fix 한다.
p 는 project 의 약어. tsconfig.json 파일에 적힌 파일 경로에서 린트될 파일을 찾는다.
package.json
1 | { |
Reference
]]>모션을 좋아하는 성향과 모션이 줄 수 있는 위의 특징때문에 곳곳에 모션을 넣는 것을 좋아하는데, 그러던 중 airbnb의 lottie
서비스가 눈에 들어왔다. 예전부터 테스트만해보고 넣어보는 것을 시도했었는데, react-native로 앱을 만드는 부분에 로딩애니메이션으로도 넣어보았지만 아직 웹에서는 넣어보지 않아서 이번 기회에 해당 블로그 header의 아바타에 움직임을 넣어보았다.
(최근 antd의 메인에서도 쓴걸 확인!)
장단점
간단 작업 순서
shape animation이나 여러가지 모션그래픽은 에프터이펙트로 작업합니다. bodymovin 플러그인을 사용하기 위해서는 after effect로 작업된 파일이 필요합니다.
작업할 때 알아야할 점 (버그)
bodymovin이라는 플러그인을 설치하고 해당 플러그인을 사용하여 렌더링 해야합니다.
설치방법
참고 > http://airbnb.io/lottie/after-effects/bodymovin-installation.html
에펙에서 "Window > Extensions"의 "Bodymovin"를 오픈하면 위의 그림처럼 창이 하나 오픈됩니다. 우리가 필요한 파일은 `json`파일과 `js`파일입니다.위의 방법대로 진행하면 오케이!
렌더링할 컴포넌트를 선택합니다.
어떤 포맷으로 렌더링할지 settings에서 선택해야합니다.
옵션은 여러가지가 있는데, 다중선택이 가능합니다.
셋팅이 완료되면 경로를 지정합니다. => 어떤 포맷으로 렌덜이되는지 확인할 수 있습니다.
위의 렌더링버튼을 누르시면 렌더링 시작.
오른쪽 상단의 get the player를 선택합니다.
왼쪽의 get the player를 누르면 js파일을 받을 수 있습니다.
hexo블로그에 셋팅할 경우 파일은 아래 경로로 옮깁니다.themes > hueman > source > js
필요한 파일
셋팅방법은 https://codepen.io/airnan/project/editor/ZeNONO/의 구조를 참고하였습니다.
1 | <script> |
해결방법
좋은 방법이라고는 생각되지 않으므로 피드백환영합니다.
index.js
의 경로를 아래처럼 수정 후,1 | // lottie_index.js |
1 | // scripts.ejs |
요약
목차
Angular CLI는 Node.js의 프로젝트이기때문에 노드의 설치가 필요하다. 노드버전은 6.9.0 이상이어야한다.
npm i -g @angular/cli
ng new 프로젝트 이름
tree src
라고 명령어를 입력하면 src 하위 파일 디렉토리 tree가 출력된다.tree -L 1
해당 디렉토리의 첫번째 레벨 트리만 출력된다.
1 | src/ |
app
폴더environments
.prod
프로젝트를 빌드할 때 프러덕션 모드로 빌드하게 되면 environment.prod.ts 내용들이 environment.ts 여기에 덮여쓰여지게된다. 앱에서 쓴 환경변수(서버 url…)를 프러덕션용 환경변수로 쓸 수 있게 된다.
1 | ng serve |
서버를 실행시키면 로컬호스트에서 확인이 가능하다.
ng help
를 입력하면 ng cli 리스트들이 쭉 나온다. 아래는 자주 사용하는 명령어만 적어둠.
ng build <options...>
--aot (Boolean) Build using Ahead of Time compilation.
--watch (Boolean) (Default: false) Run build when files change.
ng completion <options...>
CLI 명령어를 자동 완성시켜주는 것을 설정하겠다 라는 커맨드이다.
ng doc <keyword> <options...>
앵귤러 공식 docs를 열어줍니다.
ng e2e <options...>
end to end 테스트를 하겠다는 것이다. 브라우저를 띄어서 테스트 하는 것.
ng eject <options...>
우리가 만든 앵귤러 CLI 프로젝트는 웹팩기반인데, webpack configuration를 밖으로 빼내어서 webpack configuration를 수정해서 프로젝트에 맞게 바꾸고 싶을 때 사용한다.
★★ ng generate <blueprint> <options...>
사용 빈도수가 높다. 우리가 새로운 컴포넌트나 라우트나 모듈, 클래스 등을 agular CLI를 통해서 만들어지는데, 각각의 만들어지는 방법이 다르다. (옵션이 다르다.)
ng get <options...>
configuration를 한번 읽어오는 것
ng lint <options...>
프로젝트의 코드의 스타일 가이드에 맞춰서 작성이 잘 되고 있는지 체킹해준다.
ng new <options...>
ng serve <options...>
어플리케이션을 서버로 띄어준다. (빌드 후에)
ng set <options...>
앵귤러 CLI는 configuration(설정파일들)들이 있는데 그것들을 셋팅해준다.
ng test <options...>
유닛테스트 관련한 CLI, 컴포넌트나 서비스등 각각의 컴포넌트를 테스트 할때
ng version <options...>
ng xi18n <options...>
다국어 처리하는 시간에 자세히 살펴보도록 한다.
.angular-cli.json
파일은 description이라고 생각하면된다.
1 | // main.ts |
platformBrowserDynamic
메서드 : 엥귤러가 우리가 만든 코드를 컴파일을 해서 실제 실행될 수 있는 자바스크립트 코드로 만들어내는데 브라우저에서 다이나믹하게 동적으로 하겠다는 메서드이다. (just-in-time으로)bootstrapModule(루트모듈)
: 우리가 사용할 어플리케이션의 루트모듈을 설정하고 앵귤러 어플리케이션을 실행시키는 것이다. 루트모듈을 부트스트랩한다 라고도 한다.
@NgModule 데코레이터의 인자로 전달되는 메타데이터에 애플리케이션 전체의 설정 정보를 기술한 루트 모듈이다.
1 | // app.module.ts |
1 | import { Component } from '@angular/core'; |
/dist/index.html
는 빌드(ng build)의 결과물로 실제 배포 시에는 서버로 이관된다.
ng serve 명령어에 의해 내장 개발 서버를 사용하여 로컬 환경에서 프로젝트를 실행(preview)하는 경우, Angular CLI 내부적으로 빌드를 자동 수행
하므로 빌드(ng build)를 별도 실행하여 /my-app/dist/index.html를 생성할 필요는 없다.
자동으로 빌드되어 가상 드라이브에 저장되어 있는 index.html를 내장개발 서버가 로드한다고 이해하면 된다.
inline.bundle.js
: 웹팩 유틸리티가 포함된 Webpack loaderpolifills.bundle.js
: polyfil 의존성 모듈(core-js, zone.js)를 번들링한 파일styles.bundle.js
: 스타일 전의를 번들링한 파일vendor.bundle.js
: 의존성 모듈(@angular/*, RxJS 등)을 번들링한 파일main.bundle.js
: 개발자가 작성한 컴포넌트, 디렉티브, 서비스 등 소스코드를 번들링한 파일
모듈이란
Webpack
으로 변경되었다. We moved the build system from SystemJS to Webpack.컴포넌트, 파이프, 서비스 등과 같은 앵귤러 어플리케이션의 주요 부분을 기능단위로 그룹핑하게 해준다.
1 | ng g m todo |
app 하위에 todo라는 폴더가 생성되고 todo.module.ts라는 모듈파일이 만들어진다.
1 | ng g c todo/todos --module todo/todo.module.ts --export |
g는 generate,
c는 component,
m은 module,
todo 밑에 todos라는 폴더를 둔다.
todos에서 만들어진 component를 관리하는 모듈을 지정해주기 위해서 --module
이라는 플래그를 사용, 관리하는 모듈 이름을 붙여준다.todo/todo.module.ts
해당 모듈파일이 다른 곳에서 사용할 수 있다는 의미의 –export라는 플래그를 추가한다. –export플래그를 추가하면 NgModule 데코레이터의 메타데이터 내부에 export 옵션이 추가되며 todoComponent가 자동으로 추가된다.
1 | import { NgModule } from '@angular/core'; |
모듈 정리
--export
플래그를 사용하는 것이다.1 | import { Component, OnInit } from '@angular/core' |
selector
.
이나 #
을 앞에 붙여서 css에서의 선택자와 유사하게 사용도 가능하다. 현재는 .
이나 #
이 없기 때문에 태그명으로 정의된 것이다.templateUrl
styleUrls
1 | ng g c todo/todos/todo –inline-template –inline-style |
template
이 생성된다.1 | <div class="title"> |
*ngFor="let todo of todos"
todos라는 객체의 todo요소들을 referencing한다고 생각하면 된다.
ngFor
Angular의 ngFor “repeater” 지시자(directive)
DOM의 모든 것(모양이나 동작 등)을 관리하기 위한 지시(명령)
이다. HTML 요소 또는 어트리뷰트의 형태로 사용하여 디렉티브가 사용된 요소에게 무언가를 하라는 지시(directive)를 전달한다.@Component
데코레이터의 메타데이터 객체의 selector 프로퍼티에 임의의 디렉티브의 이름을 정의한다.ngClass
, ngStyle
와 같은 빌트인 어트리뷰트 디렉티브가 있다.*
를 접두사로 추가하며 []
를 사용하지 않는다.ngIf
ngIf 디렉티브는 우변 표현식의 연산 결과가 참이면 해당 요소(호스트 요소)를 DOM에 추가하고 거짓이면 해당 요소(호스트 요소)를 DOM에서 제거한다. 우변의 표현식은 true 또는 false로 평가될 수 있어야한다.
1 | <element *ngIf="expression">...</element> |
ngIf 디렉티브 앞에 붙은 *(asterisk)는 아래 구문의 문법적 설탕(syntactic sugar)이다. 즉 위 코드는 아래의 코드로 변환된다.
1 | <ng-template [ngIf]="expression"> |
Angular는 ngIf를 만나면 호스트 요소를 ng-template
디렉티브로 래핑하고 *ngIf를 *프로퍼티 바인딩으로 변환한다.**([ngIf]="expression"
) ngFor와 ngSwitch 디렉티브도 동일한 패턴을 따른다.
ngIf else
1 | <!-- if else --> |
ngFor
ngFor 디렉티브는 컴포넌트 클래스의 컬렉션을 반복하여 호스트 요소(ngFor 디렉티브가 선언된 요소) 및 하위 요소를 DOM에 추가한다. 컬렉션은 일반적으로 배열을 사용한다.
1 | <element *ngFor="let item of items">...</element> |
인덱스를 취득할 필요가 있는 경우, 인덱스를 의미하는 index를 사용하여 변수에 인덱스를 할당받을 수 있다. index 이외에도 first, last, even, odd와 같은 로컬 변수가 제공된다. 자세한 내용은 ngFor API reference를 참조하기 바란다.
ngFor 디렉티브 앞에 붙은 *(asterisk)는 아래 구문의 문법적 설탕(syntactic sugar)이다. 즉 위 코드는 아래의 코드로 변환된다.
1 | <ng-template ngFor let-item [ngForOf]="items"> |
ngSwitch
1 | <element [ngSwitch]="expression"> |
ngSwitch 디렉티브 앞에 붙은 *(asterisk)는 아래 구문의 문법적 설탕(syntactic sugar)이다. 즉 위 코드는 아래의 코드로 변환된다.
1 | <element [ngSwitch]="expression"> |
ready()
제이쿼리 ready
메서드는 DOM이 완전히 로드되었을 때 코드를 실행하도록 구현되어있다.
(리액트의 componentDidMount
)
제이쿼리 3.0 이전 버전에서는, ready 메서드를 호출할 수 있는 몇 가지 방법이 있다.
document
엘리먼트로 호출 : $(document).ready(handler);
$().ready(handler);
$(handler);
ready 이벤트는 DOM이 로드되고 엘리먼트 접근이 안전할 때 발생한다.
(= ready는 document 객체에 한해서만 적용되는 메소드.)
반대로 load 이벤트는 DOM과 모든 어셋들이 로드된 이후에 발생한다.
form태그 안에 hidden타입 input을 넣어 폼전송에 필요한 데이터를 담아 사용합니다. 혹은 보이지 않는 변수를 선언할 때 사용.
$(셀렉터).함수();
1 | <head> |
1 | $("#txt1").val("text2") |
$('#div1').attr("style", "color:red;")
GET: $("#node1").html()
SET(html): $("#node1").html("<h1>테스트</h1>")
SET(text): $("#node1").text("<h1>테스트</h1>")
: html화 하지 않고 텍스트로만 출력된다.
1 | <div id="node1"> |
before()
after()
prepend()
append()
$("input[name=rad]:checked").val()
text
: 기본값. 한 줄의 텍스트 입력 칸을 만듦 (기본 너비 문자는 20)
password
: text 속성과 같지만, 문자를 숨겨서 표시 (별표)
checkbox
: 체크박스를 만듦
radio
: 라디오 버튼 만듦
button
: 누름 버튼
submit
: 전송 버튼
reset
: 재설정 버튼
file
: 파일 선택 창을 만듦.
hidden
: 사용자에게 보이지 않는 숨김 창을 만듦.
image
: 이미지로 된 전송 버튼을 만듦 (src 속성으로 이미지 url 지정)
color
: 색상 선택 창을 만듦.
date
: 날짜 입력 창을 만듦 (년/월/일)
datetime
: 날짜 시간 창을 만듦 (년/월/일/시/분/초/초의 분할) 표준시간
datetime-local
: 날짜 시간 차응ㄹ 만듦 (년/월/일/시/분/초/초의 분할) 표준시간 없음
email
: email 주소 창을 만듦
month
: 달과 년 창을 만듦 (표준 시간 없음)
number
: 숫자 입력을 위한 창을 만듦(숫자 제한을 둘 수도 있음)
range
: 정확한 값이 중요하지 않는 숫자를 입력하는 창을 만듦 (슬라이더 장치처럼)
search
: 검색 창을 만듦
tel
: 전화번호 입력창을 만듦
time
: 시간 입력 창을 만듦 (표준 시간 없음)
url
: 주소 입력 창
week
: 주와 년 입력 창 (표준시간 없음)
$("div:eq(0)").css("color:red;")
: div:eq(0)
란, div엘리먼트들 중에서 첫번째 div요소
클래스 제어하기
addClass("클래스명")
클래스명을 지정된 셀렉터에 추가한다.removeClass("클래스명")
클래스명을 지정된 셀렉터로부터 지운다.hasClass("클래스명")
클래스명이 지정된 셀렉터로부터 존재하는지 여부를 판단. (return으로 boolean값)parent()
: 부모노드find()
: 자식노드중 태그명을 찾는다.prev()
: 같은 레벨에서의 직전 노드next()
: 같은 레벨에서 다음 노드 (직후)
each()
함수에 대해서 알아보자.1 |
|
click
on('click')
과의 차이점 : on을 사용하게되면, 추가된 요소에 더 적은 메모리를 사용하고 작업할 수 있기 때문에 .click
보다 더 선호한다. (참고)click
을 사용할 때1 | $("button.alert").click(function() { |
.on
을 사용할 때1 | $("div#container").on('click', 'button.alert', function() { |
동적으로 생성 된 요소를 포함하여 선택기와 일치하는 모든 요소에 대한 단일 처리기이다.
keypress
: 콜백함수에서 이벤트 객체를 받을 수 있는데, 내부에 keyCode값이 있어서 어떤 키보드를 누르는지에대한 정보를 얻을 수 있다. keyup
: esc의 경우에는 keypress가 아니라 keyup에서 작동된다.html로 받는 형태로만 정리하겠음.
1 | $.ajax({ |
json 렌더하기
1 | $(function () { |
trim()
1 | var text = $('#test').val() |
remove()
empty()
$("#showhide").empty();
: showhide라는 아이디값을 갖고 있는 요소의 자식요소들이 비워진다.$("#showhide").remove();
: showhide라는 아이디값을 갖고 있는 요소가 삭제된다.(아예)
선택한 태그의 인덱스값만 알고싶을 때
1 |
|
목차
1 | var targetStr = 'This is a pen.'; |
플래그는 옵션이므로 선택적으로 사용한다.
플래그를 사용하지 않은 경우 문자열 내 검색 매칭 대상이 1개 이상이더라도 첫번째 매칭한 대상만을 검색하고 종료한다.
i
: ignore Case : 대소문자를 구별하지 않고 검색한다.g
: Global : 문자열 내의 모든 패턴을 검색한다.m
: Multi Line : 문자열의 행이 바뀌더라도 검색을 계속한다.패턴에는 찾고자 하는 대상을 문자열로 지정한다.
또한 패턴은 특별한 의미를 가지는 메타문자(Metacharacter) 또는 기호로 표현할 수 있다.
/.../
1 | var targetStr = 'AA BB Aa Bb'; |
.
은 임의의 문자 한 개를 의미한다. 문자의 내용은 무엇이든지 상관없다. 위의 경우 .
를 3개 연속하여 패턴을 생성하였으므로 패턴과 일치하는 3자리 문자를 추출한다.
플래그가 없으므로 추출을 반복하지 않는다. 문자열 내의 모든 패턴을 검색하기 위해 g
사용
1 | var targetStr = 'AA BB Aa Bb'; |
+
|
[]
1 | var targetStr = 'AA BB Aa Bb'; |
앞선 패턴을 최소 한번 반복하려면 앞선 패턴 뒤에 +
를 붙인다. 아래의 경우 앞선 패턴는 A이므로 A+는 AA 또는 A를 의미한다.
1 | var targetStr = 'AA AAA BB Aa Bb'; |
|
를 사용하면 or의 의미를 가지게 된다.
1 | var targetStr = 'AA BB Aa Bb'; |
분해되지 않은 단어 레벨로 추출하기 위해서는 +를 같이 사용하면 된다.
1 | var targetStr = 'AA AAA BB Aa Bb'; |
위 예제는 패턴을 or로 한번 이상 반복하는 것인데 간단히 표현하면 아래와 같다.[]
내의 문자는 or로 동작한다. 그 뒤에 +
를 사용하여 앞선 패턴을 한번 이상 반복하게 한다.
1 | var targetStr = 'AA BB Aa Bb'; |
1 | var targetStr = 'AA BB ZZ Aa Bb'; |
\w
1 | var targetStr = 'AA BB Aa Bb'; |
\w
는 알파벳과 숫자를 의미한다. \W
는 \w
와 반대로 동작한다.
1 | var targetStr = 'AA BB Aa Bb 24,000'; |
1 | var targetStr = 'AA BB Aa Bb 24,000'; |
,
때문에 분리되는 것을 막기 위해 ,
를 범위 안에 포함시킨다.
1 | var targetStr = 'AA BB Aa Bb 24,000'; |
숫자 추출하기를 간단하게 표현하면 아래와 같다.\d
는 숫자를 의미한다. \D
는 \d
와 반대로 동작한다.
1 | var targetStr = 'AA BB Aa Bb 24,000'; |
^
1 | var targetStr = 'abcdef'; |
$
1 | var targetStr = 'abcdef'; |
1 | var targetStr = '12345'; |
\s
\s
는 공백을 의미한다.
1 | var targetStr = ' Hi!'; |
{}
{}
: 자리수를 의미한다.
1 | var targetStr = 'abc123'; |
1 | var targetStr = 'ungmo2@gmail.com'; |
1 | var targetStr = '010-1234-5678'; |
1 | var targetStr = 'abc#123'; |
요즘 작업 중인 프로젝트에서 평소에 했던 방식처럼 한 기능 당, 한 테스크당 브랜치를 생성해서 작업하고 있었다. 개인프로젝트이기 때문에.. 따로 dev 브랜치는 만들진 않았고 master에서 작업 브랜치를 만들었는데,
master
에서 Search-Todo
라는 브랜치를 생성Move Todo to Timer
라는 브랜치 생성Move Todo to Timer
에서 작업하다 잘 안되는 부분이 있어서 다른 기능 구현시작. Search-Todo
로 돌아가서 Add-Sound
브랜치 생성Add-Sound
작업이 잘 완료되어서 Search-Todo에 rebase 시킴Move Todo to Timer
작업이 끝나서 Search-Todo
에 rebase 시키기로 함문제 발생 지점
git add .
, git rebase --continue
하면 다음 커밋 비교로 넘어감.Search-Todo
브랜치에서 error..Cannot read property 'IsAndroid' of undefined
이 에러를 넘어가질 않음.
나와 같은 문제를 겪은 사람 찾음
Move Todo to Timer
로 돌아가봄.잘 작동됨
Search-Todo
로 돌아가서 확인했는데어랏? 잘 잘동됨
하 안됨.
😵
문제가 발생했던 5번 이전으로 돌아가는게 그냥 좋겠다는 생각을 했음.
git reset --hard 커밋주소
Move to Timer
) 다시 작업 후 master에 merge 시킴Search-Todo
에서 충돌 전 커밋 cherry-pick
으로 갖고와도 됐는데참고링크
rebase https://backlog.com/git-tutorial/kr/stepup/stepup6_4.html
cherry-pick https://backlog.com/git-tutorial/kr/stepup/stepup2_8.html
DNS(도메인 네임 시스템)는 .com
또는 .net
과 같은 특정 최상위 도메인(TLD)의 모든 도메인 네임 및 해당하는 IP 주소를 저장하는 데이터베이스입니다. DNS는 인터넷에서 컴퓨터 시스템과 리소스를 식별하고 찾습니다. 예를 들어, 웹 주소 또는 URL을 입력하면 DNS가 입력된 이름과 해당 위치의 IP 주소를 일치시키고 사용자를 해당 사이트에 연결시켜 줍니다.
서브넷(subnet)은 “subnetwork”을 줄인 말로서 어떤 기관에 소속된 네트웍이지만 따로 분리되어 있는 한 부분으로 인식될 수 있는 네트웍을 말한다.
일반적으로 하나의 서브넷은 하나의 지역, 한 빌딩 또는 같은 근거리통신망 내에 있는 모든 컴퓨터들을 나타낼 수 있다.
여러 개의 서브넷으로 나뉘어진 어떤 조직의 네트웍은 인터넷에 하나의 공유된 네트웍 주소로 접속될 수 있다. 만약 서브넷이 없다면, 그 조직은 물리적으로 분리된 서브 네트웍마다 하나씩, 여러 군데의 인터넷 접속을 가지게 될 것이며, 그렇게 함으로써 한정된 량의 인터넷 주소가 쓸모 없이 낭비될 수도 있게된다.
인터넷은 네트웍 사용자들 간에 서로 커뮤니케이션을 하기 위한 네트웍의 집합이다.
커뮤니케이션을 위해서는 양측의 사용자 또는 호스트가 관련되어 있는 발신지와 도착지 네트웍, 그리고 네트웍 내의 특정한 컴퓨터의 주소가 있어야 한다. 이 주소를 IP 주소라고 부른다.
32 비트의 IP 주소는 크게 두 부분으로 나뉘는데, 하나는 네트웍을 식별하는 네트웍 번호이고, 다른 하나는 네트웍 내의 특정한 컴퓨터나 호스트를 식별하는 호스트 번호이다.
한 기관에서 특정한 서브넷을 확인시키기 위해 컴퓨터나 호스트를 식별하는 주소 내의 비트들을 일부 사용할 수 있다.
그러므로 실제로는 IP 주소에는 네트웍 번호, 서브넷 번호, 그리고 컴퓨터 번호 등 세 부분이 포함되어 있는 셈이다.
NAT는 외부 네트웍에 알려진 것과 다른 IP 주소를 사용하는 내부 네트웍에서, IP 주소를 변환하는 것이다.
일반적으로, 한 회사는 자신의 내부 네트웍 주소를 하나 또는 그 이상의 공인 IP 주소로 사상한다. 그리고 들어오는 패킷들 상의 공인 IP 주소를 다시 사설 IP 주소로 변환한다.
이렇게 함으로써 나가거나 들어오는 각 요구들은 주소 변환과정을 반드시 거쳐야 하기 때문에,
보안문제를 확실하게 하는데 도움이 되며, 또한
요구를 제한하거나 인증하고, 또
이전의 요구와 일치시키는 기회를 제공한다.
NAT은 또한 회사에서 필요한 공인 IP 주소의 수를 보존하며, 회사가 외부 네트웍과의 통신에서 단 하나의 공인 IP 주소를 사용할 수 있게 한다.
NAT은 라우터의 일부로서 포함되며, 종종 통합된 방화벽의 일부가 되기도 한다.
네트웍 관리자들은 공인 IP 주소에서 사설 IP 주소로, 사설 IP 주소에서 공인 IP 주소로 사상하기 위한 NAT 표를 만든다.
NAT은 라우팅 정책과 함께 사용될 수도 있다.
NAT은 IP 주소를 정적으로 정의하거나, 또는 동적으로 변환하도록 설정될 수 있다. 시스코에서 만든 NAT 버전은 관리자가 다음과 같은 것들의 사상을 위한 표를 만들도록 해 준다.
네트워크의 입출력단자들을 포트(PORT)라고 하며 번호로 지정되는데 포트의 번호는 0에서 65535까지 입니다.
TCP/IP 네트웍에서 포트 번호는, 들어오는 트래픽을 컴퓨터 내에서 실행되고 있는 적절한 프로그램에 분배시키기 위해 할당되는 숫자를 말한다. 이것은 물리적인 플러그나 소켓이 아니며, 다만 논리적인 할당일 뿐이다
이 포트들은 크게 세 가지 영역으로 나누어서 지정되어 있습니다.
well-known port number 라고 하며 미리 특수용도로 지정되어 있습니다. (IANA(Internet Assigned Numbers Authority)에서 관리한다.)
21번: FTP
22번: SSH
23번: TELNET
25번: SMTP(이메일송신)
53번: DNS
61번: SNMP(네트워크관리)
80번: HTTP(웹페이지를 열기 위한 용도)
110번: POP3(이메일수신)
115번: SFTP
135번: RPC
139번: NetBIOS
143번: IMAP
194: IRC
443: SSL
445: SMB
1433: MSQL
3306: MySQL
3389: Remote Desktop
5632: PCAnywhere
5900: VNC
6112: Warcraft III
클라이언트/서버 방식의 프로그램에서 포트의 사용
두 프로그램이 네트워크를 통해 서로 통신을 수행할 수 있도록 양쪽에 생성되는 링크의 단자입니다.
두 소켓이 연결되면 서로 다른 프로세스끼리 데이터를 전달할 수 있습니다.
결국 소켓이 구현됨으로써 네트워크 및 전송 계층의 캡슐화가 가능해집니다.
소켓은 원래 캘리포니아 버클리 대학 분교에서 UNIX용으로 개발되었으며, UNIX에서의 입출력 메소드의 표준인 개방/읽기/쓰기/닫기 메커니즘을 따릅니다.
소켓 함수는 동기모드(블록킹) / 비동기 모드 (논블록킹)으로 동작합니다.
차이점은 만약 데이터가 도착하지 않는 상태에서 recv()로 데이터를 수신하고자 했을 때 데이터가 올 때까지 대기(block)하느냐 , 그냥 수신된 데이터가 없다는 정보만 리턴하고 넘어가느냐 입니다.
실제로 대기한다는 의미는 시스템을 멈추고 기다린다는 것이 아니라 다른 쓰레드나 프로세스(process)로 실행 권을 넘기는 것이기 때문에 프로세서는 항상 적절한 동작을 하게 됩니다.
비동기 모드로 데이터가 올 떄까지 풀링(polling)하면서 대기하는 것과는 기다린다는 의미에서는 동일하지만 프로세서를 활용한다는 면에서는 하늘과 땅 차이라고 할 수 있습니다. 이런 병렬적인 처리에 대한 고려가 필요하게 됩니다.
그리고 직접적인 소켓 통신을 처리하는 함수는 아니지만 소켓 처리에 대해서 Multiplex처리(하나의 쓰레드, 혹은 적은 수의 쓰레드에서 여러 개의 소켓을 처리)를 해주는 select , epoll , IOCP 같은 기능적인 함수군도 염두해 두어야겠습니다.
MAC 주소는, 무선 LAN 카드 또는 무선 LAN 기능 내장 기기에 개별적으로 부여되는 16진수 12자리의 단말 식별 번호(예:12:34:56:78:90:AB)입니다. OS에 따라 “물리적 주소” 또는”Wi-Fi 주소”라고 표시됩니다.
Client와 Server 또는 P2P Socket 통신 등, 네트워크를 사용한 통신시 TCP 통신을 많이 사용한다.
TCP 통신을 위한 네트워크 연결은 3 way handshake 라는 방식으로 연결된다.
쉽게 이야기 하면, 서로의 통신을 위한 관문(port)을 확인하고 연결하기 위하여 3번의 요청/응답 후에 연결이 되는 것이다.
먼저 Server에서 열려있는 포트는 LISTEN 상태이고 Client에서는 Closed 상태이다.
Client에서 Server에 연결 요청을 하기위해 SYN 데이터를 보낸다. (SYN = synchronize sequence numbers)
Server에서 해당 포트는 LISTEN 상태에서 SYN 데이터를 받고 SYN_RCV로 상태가 변경된다.
그리고 요청을 정상적으로 받았다는 대답(ACK)와 Client도 포트를 열어달라는 SYN 을 같이 보낸다.
(ACK = acknowledgment)
Client에서는 SYN+ACK 를 받고 ESTABLISHED로 상태를 변경하고 서버에 요청을 잘 받았다는 ACK 를 전송한다.
ACK를 받은 서버는 상태가 ESTABLSHED로 변경된다.
위와 같이 3번의 통신이 정상적으로 이루어지면, 서로의 포트가 ESTABLISHED 되면서 연결이 되게 된다.
현재의 포트 상태 확인은 netstat 명령어로 할 수 있다.
‘프론트엔드 개발자를 위한 자바스크립트 프로그래밍’ 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
목차
DOM은 그 자체로도 매우 잘 정의된 API이긴 하지만, 특정 브라우저 전용 방법으로 확장하여 기능을 추가할 때도 많다.
querySelector()
querySelectorAll()
1 | // body 요소를 가져온다. |
"h1, h2, h3"
요소간 이동 API에서 추가된 새 프로퍼티들
childElementCount
: 자식 요소 숫자를 반환하되 텍스트 노드와 주석은 제외한다.firstElementChild
: 첫번째 자식 요소를 가리킨다. lastElementChild
: 마지막 자식 요소를 가리킨다.previousElementSibling
: 이전 형제 요소를 가리킨다. nextElementSibling
: 다음 형제 요소를 가리킨다. getElementsByClassName()
메서드1 | // HTMLCollection을 반환한다. |
HTMLCollection은 실시간으로 Node의 상태 변경을 반영한다. (live HTMLCollection)
실시간으로 Node의 상태 변경을 반영하기 때문에 loop가 필요한 경우 주의가 필요하다.
아래와 같은 방법으로 회피할 수 있다.
방법1 > 역방향으로 돌리기
1 | var elems = document.getElementsByClassName('red'); |
방법2 > none-live NodeList를 반환하는 querySelectorAll을 사용한다.
1 | // querySelectorAll는 Nodelist(non-live)를 반환한다. IE8+ |
className
프로퍼티를 이용해 클래스 이름을 추가하거나 제거, 교체했다.DOMTokenList의 메서드
document.activeElement
document.hasFocus()
<head>
프로퍼티document.head
로도 <head>
요소 참조가 가능하다.document.charset
document.defaultCharset
data-
DOMStringMap
인스턴스이다.마크업이 포함된 콘텐츠를 추가하는 것은 크로스 스크립팅 공격(XSS: Cross-Site Scripting Attacks)에 취약하다.
삽입할 위치 매개변수
beforebegin
: 호출한 요소 바로 앞에 삽입afterbegin
: 호출한 요소 첫번째 자식 요소 바로 앞에 삽입beforeend
: 호출한 요소 마지막 자식 요소 바로 다음에 삽입afterend
: 호출한 요소 바로 다음에 삽입모든 HTML요소에 존재하며 브라우저 창이나 컨테이너 요소를 스크롤해서 해당 요소가 뷰포트에 보이게 한다.
‘프론트엔드 개발자를 위한 자바스크립트 프로그래밍’ 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
목차
document.createTextNode()
normalize()
를 사용하면 두 가지 텍스트가 공백없이 합쳐진다.1 | const element = document.createElement("div"); |
normalize()
splitText()
‘프론트엔드 개발자를 위한 자바스크립트 프로그래밍’ 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
넘나 많은 프로퍼티와 메서드들 @_@
브라우저는 웹 문서(HTML, XML, SVG)를 로드한 후, 파싱하여 DOM(문서 객체 모델: Document Object Model)을 생성한다.
텍스트 파일로 만들어져 있는 웹 문서를 브라우저에 렌더링하기 위해서는 웹 문서를 브라우저가 이해할 수 있는 구조로 메모리에 올려야 한다.
브라우저의 렌더링 엔진은 웹 문서를 로드한 후, 파싱하여 웹 문서를 브라우저가 이해할 수 있는 구조로 구성하여 메모리에 적재하는데 이를 DOM이라 한다.
즉 모든 요소와 요소의 어트리뷰트, 텍스트를 각각의 객체로 만들고 이들 객체를 부자 관계를 표현할 수 있는 트리 구조로 구성한 것이 DOM이다.
이 DOM은 자바스크립트를 통해 동적으로 변경할 수 있으며 변경된 DOM은 렌더링에 반영된다.
이러한 웹 문서의 동적 변경을 위해 DOM은 프로그래밍 언어가 자신에 접근하고 수정할 수 있는 방법을 제공하는데 일반적으로 프로퍼티와 메소드를 갖는 JavaScript 객체로 제공된다.
이를 DOM API(Application Programming Interface)라고 부른다.
달리 말하면 정적인 웹페이지에 접근하여 동적으로 웹페이지를 변경하기 위한 유일한 방법은 메모리 상에 존재하는 DOM을 변경하는 것이고, 이때 필요한 것이 DOM에 접근하고 변경하는 프로퍼티와 메소드의 집합인 DOM API이다.
DOM은 HTML, JavaScript에서 정의한 표준이 아닌 별개의 W3C의 공식 표준이며 플랫폼/프로그래밍 언어 중립적이다. DOM은 다음 두 가지 기능을 담당한다.
목차
<html>
)—- 2편 👇
1 | <html> |
노드 타입
은 모두 이 인터페이스를 구현한다.모든 노드에는 타입을 나타내는 nodeType 프로퍼티가 있다.
1 | Node.ELEMENT_NODE (1) |
1 | if (someNode.nodeType == Node.ELEMENT_NODE){ |
null
이다.NodeList
가 저장된다.유사배열 객체
노드를 순서 있는 목록으로 저장하여 위치 기반으로 접근 가능.
length
프로퍼티 : 호출 당시 노드리스트에 담긴 노드 숫자임을 기억하자.
Array의 인스턴스는 아니다.
DOM 구조의 쿼리 결과
계속 바뀌므로 살아있는 객체라고도 부른다.
childNodes는 모든 자식요소 찾기
children은 모든 자식요소 찾기이지만 요소노드만 찾는다.
노드 리스트에 저장된 노드를 접근하는 방법 (어느쪽을 더 권잔하진 않는다.)
1 | const firstChild = someNode.childNodes[0]; |
previousSibling
및 nextSibling
프로퍼티로 이동할 수 있다.childNodes 목록에서 첫번째 노드를 가리킨다.
someNode.firstChild = someNode.childNodes[0]
childNodes 목록에서 마지막 노드를 가리킨다.
someNode.lastChild = someNode.childNodes[someNode.childNodes.length-1]
노드에 자식 노드가 있으면 true를 반환.
length로 자식 노드 확인하는 것보다 효과적.
전체 문서를 표현하는 문서 노드에 대한 포인터
노드 계층 구조를 따라 위로 거슬러 올라갈 필요 없이 문서 노드에 빠르게 접근 가능하다.
appendChild()
insertBefore(삽입할 노드, 기준 노드)
replaceChild(삽입할 노드, 교체할 노드)
removeChild()
cloneNode(boolean)
고아노드
라고 한다.1 | <ul> |
1 | const deepList = myList.cloneNode(true) // myList에 ul요소에 대한 참조를 저장했다고 가정 |
nomalize()
nomalize
를 호출하면 노드의 자손에서 이 두가지 상황이 생기지 않았는지 검색한다.HTMLDocument
의 인스턴스window.document
Document 노드의 특징
Document 자식으로
documentElement
프로퍼티HTML페이지의 <html>
요소를 가리킨다.
childNodes의 document 요소보다 documentElement프로퍼티가 해당 요소에 더 빨리, 더 직접적으로 접근한다.
1 | const html = document.documentElement; |
document 객체는 HTMLDocument의 인스턴스이므로 <body>
요소를 직접적으로 가리키는 body 프로퍼티를 갖는다.
document 객체
DocumentType
<!DOCTYPE>
태그는 문서의 다른 부분과는 별도의 엔티티로 간주하며 포함된 정보는 다음과 같이 doctype 프로퍼티를 통해 접근할 수 있다.
1 | const doctype = document.doctype |
document.title
<title>
요소 텍스트가 들어있다.HTTP 헤더에 들어있다.
특정 요소나 요소 그룹에 대한 참조를 얻는 일을 자주한다.
대표적인 2가지 메서드. getElementById()
, getElementByTagName()
getElementById()
getElementByTagName()
1 | <img src="myimage.jpg" name="myImage"> |
1 | const images = document.getElementByTagName("img") |
item()
사용namedItme()
사용*
를 사용한다.1 | const allElements = document.getElementByTagName("*") |
getElementByName()
name 속성 값이 주어진 문자열에 일치하는 요소를 반환한다.
1 | <fieldset> |
document객체에는 특별하 컬렉션이 몇가지 있다.
각 컬렉션은 모두 HTML Collection 객체이고,
문서에 공통된 요소들에 빠르게 접근할 수 있도록 만들어졌다.
document.anchors
: name속성이 있는 <a>
요소를 모두 갖고온다.document.applets
: <applet>
요소를 모두 갖고온다. document.forms
: <form>
요소를 모두 가져온다. (document.getElementsByTagName(“form”)과 같다.)document.images
: <img>
요소를 모두 갖고온다.document.links
: href속성이 있는 <a>
요소를 모두 가져온다.hasFeature()
write()
: 넘겨 받은 텍스트를 그대로 추가하고writeIn()
: 줄바꿈을 문자(\n
)를 문자열 마지막에 추가한다.open()
: 페이지 스트림을 열고close()
: 페이지 스트림을 닫습니다.
Element 요소의 특징
HTMLElement 타입을 통해 표현된다.
HTMLElement는 Element를 직접적으로 상속한다.
id
: 요소의 고유한 식별자title
: 요소에 대한 추가 정보, 일반적으로 툴팁으로 표현됨lang
: 요소 콘텐츠의 언어 코드. 거의 사용되지 않는다.dir
: 언어의 표기 반향. ltr
은 왼쪽 => 오른쪽, rtl
은 오른쪽 => 왼쪽. 거의 사용되지 않는다.className
: CSS 클래스인 class 속성을 나타낸다. class가 ECMAScript의 예약어이기 때문에 className이라고 사용한다.
1 | <div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div> |
getAttribute()
)getAttribute(속성이름)
: 공식 속성 이외에 커스텀 속성을 가져오는데도 쓸 수 있다.setAttribute(속성이름, 속성이름의 값)
removeAttribute(속성이름)
data-
를 붙여야 유효한 것으로 인정한다.1 | var four = document.getElementById('four'); |
setAttribute()
)removeAttribute()
)NamedNodeMap
이 저장된다.getAttribute()
, removeAttribute()
, setAttribute()
메서드가 더 많이 사용된다.NamedNodeMap 객체의 메서드들
getNamedItem(name)
: nodeName 프로퍼티가 name인 노드를 반환한다.removeNamedItem(name)
: nodeName 프로퍼티가 name인 노드를 목록에서 제거한다.setNamedItem(node)
: node를 목록에 추가하고 nodeName 프로퍼티에 따라 색인한다. item(pos)
: 인덱스가 pos인 노드를 반환한다.attributes 메서드들이 유용한 경우는 요소의 속성을 대상으로 루프가 필요할 때.
각 속성의 이름과 값을 문자열에 추가한다.
1 | function outputAttributes(element) { |
document.createElement()
)요소는 자식 요소나 자손 요소를 가질 수 있고, 그 숫자는 제한이 없다.
1 | <ul id="myList"> |
<ul>
요소 자식 노드가 7개 생긴다.
<li>
는 3개, <text>
4개 (<li>
와 텍스트 사이의 공백)‘프론트엔드 개발자를 위한 자바스크립트 프로그래밍’ 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
목차
—- 1편 👆
window.location
과 document.location
은 같은 객체를 가리킨다. location의 프로퍼티들을 살펴보자.
hash
(예: “#/0/1” http://slides.com/nayoung/deck-8#/0/1)host
(예: “localhost:4000”)hostname
(예: “localhost”)href
(예: “http://localhost:4000/2017/12/28/JS_07/")toString()
메서드는 이 값을 반환pathname
(예: “/2017/12/28/JS_07/“)port
(예: “4000”)protocol
(예: “http:”)스키마
라고 부르기도 한다.search
(예: “?q=window”)URL 정보 중 쿼리스트링은 다루기 쉬운 형태로 제공되지 않는다.
즉, 하나씩 분리해서 제공하지 않는다는 말.
아래 함수를 이용하면 쿼리스트링을 파싱해서 각 매개변수를 프로퍼티로 갖는 객체를 반환한다.
1 | function getQueryStringArgs(teset){ |
결과
1 | https://www.google.co.kr/search?newwindow=1&tbm=isch&q=그리드+다단&cad=h |
decodeURIComponent
HTML에서 한글이 섞인 주소는 오작동할 수 있기 때문에 이스케이프 시켜야한다.
예 : “나영” => “%EB%82%98%EC%98%81”
이를 인코딩
이라고 하며, 반대로 다시 언어화를 시켜주는 디코딩
이 있습니다.decodeURIComponent
는 http://
부터 모두 디코딩을 해줍니다.
#
와 함께 인자가 URL 뒤에 추가된다.q=
뒤에 검색 단어를 추가한다.1 | // https://developer.mozilla.org/ko/?q=nayn |
위의 프로퍼티들은 브라우저 히스토리 스택에 쌓이기 때문에 뒤로가기 버튼이 적용된다.
replace는 그렇지 않다.
매개변수 없이 호출하면
페이지를 가능한 한 가장 효과적인 방법으로 다시 읽는다.매개변수로 true를 넘기면
서버에서 읽어오도록 강제하게된다.클라이언트에서 브라우저를 구별하는 방법의 표준으로 쓰였다.
navigator 객체의 프로퍼티는 일반적으로 웹 페이지를 실행 중인 브라우저 타입을 판단하는 데 사용한다.
( *은 크롬 )
프로퍼티/메서드 | 설명 | IE | 파이어폭스 | 사파리/크롬 | 오페라 |
---|---|---|---|---|---|
*appCodeName | 브라우저 이름이다. 모질라 브라우저가 아니어도 일반적으로 “Mozila” | 3.0+ | 1.0+ | 1.0+ | 7.0+ |
appMinorVersion | 추가적인 버전 정보이다. | 4.0+ | - | - | 9.5+ |
*appName | 완전한 브라우저 이름이다. | 3.0+ | 1.0+ | 1.0+ | 7.0+ |
*appVersion | 브라우저 버전입니다. 일반적으로 브라우저 실제 버전과는 다르다. | 3.0+ | 1.0+ | 1.0+ | 7.0+ |
buildID | 브라우저의 빌드 번호이다. | - | 2.0+ | - | - |
*cookieEnabled | 쿠키가 활성화되어 있는지 나타낸다. | 4.0+ | 1.0+ | 1.0+ | 7.0+ |
cpuClass | 클라이언트 컴퓨터의 CPU 타입이다. “x86”, “68K”, “Alpha”, “PPC”, “Ohter”가 있습니다. | 4.0+ | - | - | - |
*javaEnabled | 브라우저에 자바가 활성화되어 있는지 나타낸다. | 4.0+ | 1.0+ | 1.0+ | 7.0+ |
*language | 브라우저의 우선적 언어(한국어, 영어..)를 나타낸다. | - | 1.0+ | 1.0+ | 7.0+ |
*mimeTypes | 브라우저에 등록된 마임 타입을 나열한 배열이다. | 4.0+ | 1.0+ | 1.0+ | 7.0+ |
onLine | 브라우저가 인터넷에 연결되어 있는지 나타낸다. | 4.0+ | 1.0+ | - | 9.5+ |
opsProfile | 브라우저가 인터넷에 연결되어 있는지 나타낸다. | 4.0+ | - | - | - |
oscpu | 거의 사용하지 않으며 문서도 없다. | - | 1.0+ | - | - |
*platform | 브라우저가 실행중인 운영체제와 CPU를 타나낸다. | 4.0+ | 1.0+ | 1.0+ | 7.0+ |
*plugins | 브라우저에 설치된 플러그인을 나열한 배열이다. IE에서는 페이지의 | 4.0+ | 1.0+ | 1.0+ | 7.0+ |
preference() | 사용자 선호사항을 설정한다. 특권모드에서만 접근가능 | - | 1.5+ | - | - |
*product | 브라우저 이름. 일반적으로 “Gecko”이다. | - | 1.0+ | 1.0+ | - |
*productSub | 브라우저에 대한 추가정보. 일반적으로 게코 버전 정보. | - | 1.0+ | 1.0+ | - |
registerContentHandler() | 웹사이트를 특정 마임 타입 처리기로 등록한다. | - | 2.0+ | - | - |
registerProtocolHandler() | 웹사이트를 특정 프로토콜 처리기로 등록한다. | - | 2.0+ | - | - |
securityPolicy | 보안 정책 이름이지만 폐기되었다. | - | 1.0+ | - | - |
systemLanguage | 운영체제의 언어이다. | 4.0+ | - | - | - |
taintEnabled() | 변수 테인트가 활성화 되어 잇는지 나타내지만 폐기된 기능. | 4.0+ | 1.0+ | - | 7.0+ |
*userAgent | 브라우저 문자열이다. | 3.0+ | 1.0+ | 1.0+ | 7.0+ |
userLanguage | 운영체제의 기본 언어이다. | 4.0+ | - | - | 7.0+ |
userProfile | 사용자 프로필 정보에 접근할 때 사용하는 객체 | 4.0+ | - | - | - |
*vendor | 브라우저 제조사 이름이다. | - | 1.0+ | 1.0+ | - |
*vendorSub | 제조사에 대한 추가 정보이다. | - | 1.0+ | 1.0+ | - |
현재 크롬의 plugins
1 | [ |
window의 프로퍼티이다.
픽셀 너비와 높이 등 클라이언트 화면에 대한 정보가 들어있다.
(*은 크롬)
프로퍼티/메서드 | 설명 | IE | 파이어폭스 | 사파리/크롬 | 오페라 |
---|---|---|---|---|---|
*availHeight | 시스템 요소를 제외한 화면의 픽셀 높이이다. | ○ | ○ | ○ | ○ |
*availLeft | 시스템 요소가 아닌 영역 중 왼쪽에서 첫 번째 픽셀이다. (읽기전용) | ○ | ○ | ||
*availTop | 시스템 요소가 아닌 영역 중 위에서 첫 번째 픽셀이다. (읽기전용) | ○ | ○ | ||
*availWidth | 시스템 요소를 제외한 화면의 픽셀 너비이다. (읽기전용) | ○ | ○ | ○ | ○ |
bufferDepth | 시스템 요소를 제외한 화면의 픽셀 너비이다. (읽기전용) | ○ | |||
*colorDepth | 색깔 비트 숫자이며 대부분 32이다. (읽기전용) | ○ | ○ | ○ | ○ |
deviceXDPI | 화면의 실제 가로 DPI이다. (읽기전용) | ○ | |||
deviceYDPI | 화면의 실제 세로 DPI이다. (읽기전용) | ○ | |||
fontSmoothingEnabled | 폰트를 부드럽게 처리하는 기술이 활성화되어있는지 나타낸다. (읽기전용) | ○ | |||
*height | 화면의 픽셀 높이이다. | ○ | ○ | ○ | ○ |
left | 현재 화면의 왼쪽 모서리로부터의 픽셀 거리이다. | ○ | |||
logicalXDPI | 화면의 논리적 가로 DPI이다. (읽기전용) | ○ | |||
logicalYDPI | 화면의 논리적 세로 DPI이다. (읽기전용) | ○ | |||
*pixelDepth | 화면의 픽셀당 비트 숫자이다. (읽기전용) | ○ | ○ | ○ | |
top | 현재 화면의 위쪽 모서리로부터의 픽셀 거리이다. | ○ | |||
updateInterval | 화면을 몇 밀리초마다 업데이트하는지 나타낸다. | ○ | |||
*width | 화면의 픽셀너비이다. | ○ | ○ | ○ | ○ |
history.go(-1)
: 한페이지 뒤로history.go(1)
: 한페이지 앞으로history.go(2)
: 두페이지 앞으로
한페이지 뒤로
한페이지 앞으로
length
: history 스택에 기록이 얼마나 많이 있는지 나타낸다. 0일경우 사용자가 페이지를 처음 열었을 때인 것이다.
‘프론트엔드 개발자를 위한 자바스크립트 프로그래밍’ 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
목차
—- 2편 👇
BOM은 웹 페이지 콘텐츠와 무관하게 브라우저 기능을 노출하는 객체
이다.
브라우저의 인스턴스 => window 객체
웹페이지에서 정의한 모든 객체, 변수, 함수에서는
window가 Global 객체(= 표준내장객체) 구실을 하고,
window에 정의된 parseInt()등의 메서드를 이용한다. +
global objects와 global object는 다르다.
global objects는 표중내장객체, global object는 전역객체이다.(실행 컨택스트에서 GO)
전역에서 선언한 변수
와 함수
는 모두
window 객체의 프로퍼티 및 메서드가 된다.
1 | const age = 29; |
delete
연산자로 제거할 수 없고, window 프로퍼티는 가능하다.1 | const age = 29; |
페이지에 프레임이 들어 있으면 각 프레임은 독자적인 window객체를 가지며, frames 컬렉션에 저장된다.
screenLeft
: 디바이스 화면 왼쪽에서 브라우저 창까지 가로 거리screenTop
: 디바이스 화면 위쪽에서 브라우저 창까지 세로 거리moveBy(가로이동 픽셀수, 세로이동 픽셀수)
: (왼->오 / 위-> 아래)moveTo(x좌표, y좌표)
moveBy
moveTo
크롬, 오페라, IE7이상은 안됨크기측정
innerWidth
: 브라우저 창 내부의 페이지 뷰포트 크기 (모바일도 가능)innerHeight
: 브라우저 창 내부의 페이지 뷰포트 크기 (모바일도 가능)outerWidth
: 브라우저 창의 크기outerHeight
: 브라우저 창의 크기크기조절 (IE6이상 크롬 오페라에서는 금지)
resizeTo(최종너비, 최종높이)
resizeBy(너비 얼만큼 바꿀지, 높이 얼만큼 바꿀지)
window.open()
: URL로 이동한 후 브라우저 창을 새로 연다.
string
boolean
1 | window.open("http://feel5ny.github.io", "topFrame") |
두번째 인자에는 _self
,_parent
,_top
,_blank
사용가능
소셜 인증시 팝업창이 open되고, close될 때 사용된다.
1 | window.open("http://feel5ny.github.io", "topFrame", |
옵션 | 값 | 설명 |
---|---|---|
fullscreen | “yes” or “no” | 브라우저 창을 최대 크기로 생성할지 나타낸다. |
height | 숫자 | 새 창의 높이이다. 최소값은 100 |
left | 숫자 | 새 창의 x좌표이다. 음수는 쓸 수 없다. |
location | “yes” or “no” | 주소 표시줄을 표시할지 나타낸다. 기본 값은 브라우저에 따라 다르다. “no”로 지정하면 브라우저에 따라 주소 표시줄을 숨기거나 비활성화한다. |
menubar | “yes” or “no” | 메뉴 바를 표시할지 나타낸다. 기본값은 “no” |
resizable | “yes” or “no” | 새 창의 테두리를 드래그해서 크기를 조절할 수 있는지 나타냅니다. 기본값은 “no” |
scrollbars | “yes” or “no” | 새 창 콘텐츠가 뷰표트를 넘칠 때 스크롤을 허용할지 나타낸다. 기본값은 “no” |
status | “yes” or “no” | 상태 바를 표시할지 나타낸다. 기본 값은 브라우저에 따라 다르다. |
toolbar | “yes” or “no” | 툴바를 표시할지 나타낸다. 기본값은 “no” |
top | 숫자 | 새 창의 y좌표. 음수는 쓸 수 없다. |
width | 숫자 | 새 창의 너비. 최솟값은 100 |
window.open()
메서드는 새로 생성한 창에 대한 참조를 반환한다.
기본적으로 주요 브라우저 창의 위치나 크기를 스크립트에서 바꿀 수 없게 금지되지만, .open으로 생성한 창은 가능하다. (크롬은 CORS에 걸림)window.close()
는 window.open()
으로 생성된 창에서만 적용가능하다.
1 | var wroxWin = window.open("http://feel5ny.github.io", "topFrame", |
wroxWin
은 opener
프로퍼티를 갖고 있는데, window.open()을 호출한 창이나 프레임을 가리키는 포인터이다.
그 역은 존재하지 않는다.
1 | var wroxWin = window.open("http://feel5ny.github.io", "topFrame", |
window에는 코드가 특정 시간에 실행되게끔 해주는 메서드가 있다.setTimeout(실해코드, 시간(밀리초))
: 일정 시간 뒤에 코드를 실행setInterval()
: 일정 시간마다 코드를 반복 실행
setTimeout()
자바스크립트는 큐를 이용해 각 코드의 실행을 관리한다.
큐? Task 큐와 이벤트 루프이다. Task 큐는 말 그대로 콜백 함수들이 대기하는 큐(FIFO) 형태의 배열이라 할 수 있고, 이벤트 루프는 호출 스택이 비워질 때마다 큐에서 콜백 함수를 꺼내와서 실행하는 역할을 해 준다.
clearTimeout(setTimeout이 할당된 변수이름. 혹은 id값)
: 타임아웃을 취소할 때 사용한다.
setInterval()
페이지가 종료되거나 인터벌을 취소하기 전에는 일정 시간마다 코드를 반복 실행한다.
1 | setInterval(function(){ |
clearInterval()
: 인터벌을 취소한다.
인터벌을 취소하지 않으면 페이지가 떠 있는 동안은 계속 실행되므로 인터벌 취소는 timeout 취소보다 중요
alert()
: Okconfirm()
: Ok / cancelprompt()
: input / Ok / cancel
window.print()
: 인쇄 대화상자 표시window.find('찾을 단어')
: 찾기 대화상자 표시
componentDidUpdate(prevProps, prevState)
< Props Update >
props가 업데이트될 때의 과정입니다. 업데이트되기 전에 업데이트가 발생하였음을 감지하고, componentWillReceiveProps 메소드가 호출됩니다. 그 후 shouldComponentUpdate, componentWillUpdate가 차례대로 호출된 후, 업데이트가 완료(render)되면 componentDidUpdate가 됩니다.이 메소드들은 첫 번째 인자로 바뀔 props에 대한 정보를 가지고 있습니다.
componentDidUpdate만 이미 업데이트되었기 때문에 바뀌기 이전의 props에 대한 정보를 가지고 있습니다.
1 | componentDidUpdate(prevProps, prevState) { // 이전 props, state에 대한 정보 |
참고링크
https://www.zerocho.com/category/React/post/579b5ec26958781500ed9955
TCP 소켓은 신뢰할 수 있는 프로토콜이다. 두 머신에서 데이터를 주고 받을 때, 파일에 쓰는 것처럼 한 쪽에서 쓰고 다른 쪽에서 읽을 수 있다.
연결은 신뢰할 수 있고 순차적이다.
즉, 한 쪽에서 보낸 데이터는 다른 쪽에서 안전하게 받을 수 있다.
TCP 소켓도 데이터 스트림이다. 데이터를 잘라 패킷에 담아 네트워크로 보낸다.
TCP가 단순할 수 있었던 기반에는 IP가 있다.
IP에는 커넥션과 관련된 컨셉은 없다. 대신 패킷이 한 컴퓨터에서 다른 컴퓨터로 전달되는 것과 관련이 있다.
교실에서 손편지를 써서 건너건너 친구에게 전달하는 걸 떠올려보자.
어떻게든 친구에게 편지가 도착하긴 하겠지만, 여러 사람을 거쳐 전달될 거다.
편지가 친구에게 정확하게 도착할 거란 보장은 없다.
단지, 잘 도착하기만 바라고 보낼 뿐이다.
편지가 잘 도착했는지 알 수 있는 방법이 없다.
물론, 실제론, 어떤 컴퓨터도 가장 빠르게 도달할 수 있는 방법을 알지 못하기 때문에 이보다 더 복잡하기도 하다.
가끔은 패킷을 복사해 여러 경로로 보낼 수도 있다. 이에 따라 각각 도착시간이 달라질 수도 있다.
다른 방법으로, 여러 컴퓨터를 거치지 않고 데이터를 주고 받을 컴퓨터끼리 직접 연결하는 건 어떨까?
이 때 UDP를 사용할 수 있다.
UDP는 “user datagram protocol”의 약자인데, TCP와 같이 IP 기반 위에 구현되어 있다.
하지만, 다른 것과 달리 간단한 작업을 하는 아주 얇은 레이어만 올려져 있다.
UDP를 사용해서, 목적지의 IP(예: 112.140.20.10) 주소와 포트(예:52432)로 메시지를 보낼 수 있고,
컴퓨터를 거쳐 거쳐 목적지까지 도달할 수도 있고, 아님 도착하지 않을 수도 있다.
받는 곳에서는 포트(52432)를 열어두고, 패킷이 올 때까지 기다린다.
이 때, 어떤 컴퓨터에서 온 것이든 모두 받아들인다. (커넥션이 없다는 것을 기억한다)
받는 쪽에서는 패킷이 도착했을 때 이게 어느 IP의 어느 포트에서 왔고 크기가 얼마나 되는지 알 수 있다.
그리곤 패킷 데이터를 읽을 수 있다.
UDP는 안정적이지 않은 프로토콜이다.
일반적으로는 1~5% 정도의 데이터를 잃는 경우가 많고, 심지어는 전혀 받지 못할 수도 있다. 패킷이 전송된 순서 또한 보장되지 않는다.
UDP는 IP에서 많은 일을 하지 않는다.
데이터가 전송될 수도 안될 수도 있지만, UDP가 보장해주는 건 데이터의 ‘양’이다.
한 쪽에서 256바이트를 보냈으면, 받는 쪽에서도 무조건 256바이트를 받는다.
처음 100바이트를 받을 수는 없다.
정리
목차
두 대 이상의 컴퓨터 들을 연결하고 서로 통신(이야기) 할수 있는 것
Local Area Network : 근거리 통신망
LAN의 토폴로지에 따라 버스형, 링형, 스타형, 계층형, 메쉬형 등으로 구분할수 있다.
*토폴로지란 (Topologies) : 네트워크를 구성하는 노드와 노드간에 연결 상태에 대한 배치를 의미한다.
신뢰성과 확장성이 좋으며 모든 노드 들이 버스에 T 자형
으로 연결 되어 상호 Point - to - Point
형태를 가지게 됩니다. 각 노드들의 연결은 어뎁터(Adapter)
를 사용하며 양 끝 단에 Terminator
를 두게 됩니다.
각 노드의 고장은 전체 네트워크 부분에 영향을 미치는 점을 가지며 CSMA/CD 방식을 주로 사용, 케이블 사용량이 적기 때문에 투자 비용이 적게 드는 편입니다.
*CSMA/CD 방식이란
통신제어가 간단하고 신뢰성이 높으며 장거리 네트워크
에서 사용 가능 합니다.링(Ring) 형태
를 이루지만 노드간 통신은 Point - to - Point
를 가지며
각 노드에서 신호 재생이 가능 하기 때문에 버스 형태와 달리 거리 제약이 적으며 잡음에도 강합니다.
중앙 제어 방식으로 모든 기기가 Point - to - Point
방식으로 연결 되어 있으며 문제 해결이 쉽고 하나의 기기의 고장은 전체에 영향을 미치지 않지만 중앙 제어 장비가 고장이 나면 모든 시스템에 영향을 미치게 됩니다. 케이블 사용량이 많으며 비용 또한 큰 편입니다.
네트워크 상의 모든 컴퓨터들이 연결되어진 형태로써 연결 된 기기나 노드가 고장나더라도 다른 경로를 통해 통신이 가능하며 어떠한 경우에도 네트워크가 동작한다는 장점을 가지게 됩니다.
하지만, 네트워크에 연결된 기기의 수가 많을 경우 모든 기기와 연결 해야 하기 때문에 케이블 사용량이 많으며
구조 또한 복잡하여 네트워크 관리가 힘들어 진다
는 단점을 가지고 있습니다.
International Network 의 합성어 로써 TCP/IP ( Transmission Control Protocol / Internet Protocol ) 을 기반으로 전세계의 네트워크를 하나로 연결 하여 각각 PC가 가지고 있는 자료나 정보를 주고 받을 수 있는 광역 네트워크를 인터넷 이라고 합니다.
*다른 정의
사람과 사람이 통신할때 서로 이해할 수 있는 언어, 공용된 언어를 사용해 전세계 모든 사람과 대화 할수 있다라고 하면, 컴퓨터와 컴퓨터도 서로 이해 할 수 있는 언어, 공용된 언어를 사용 해야 한다는 것인데 이 것이 바로 프로토콜(Protocol) 입니다.
어떤 시스템이 다른 시스템과 통신을 원활하게 수용하도록 해주는 통신 규약, 약속
프로토콜의 기능으로써
순서 결정
세분화와 재합성
프로토콜은 특성에 따라 여러가지 형태로 분류할수 있으며 각각 형태를 구분 지어 본다면
네트워크 용어에서 나오는 P 는 Protocol 의 약자가 대부분이며 대표적으로 인터넷을 할 때 사용되는 프로토콜은 TCP/IP 가 있습니다.
TCP/IP 는 Transmission Control Protocol / Internet Protocol 의 약자로써 컴퓨터와 컴퓨터가 통신 회선 등으로 연결 하기 위한 통신 규약입니다.
그외 HTTP, ARP, ICMP, SNMP, SMTP, POP, FTP, TFTP, DHCP 등이 프로토콜의 종류입니다.
Relational Database Management System
Table 자체를 구성하는대 사용한다.
Create
: db 스키마 객체를 생성1 | CREATE TABLE book ( |
Data Type
VARCHAR2(size)
: 가변길이 문자열 (최대 4000byte)CHAR(size)
: 고정길이 문자열 (최대 2000byte)NUMBER(p,s)
: 가변길이 숫자. 전체 p자리 중 소수점 이하 s자리p
: 38s
: -84 ~ 127DATE
: 고정길이 날짜 + 시간 (7byte)Alter
: 변경ALTER Table Student ADD (name VARCHAR(50));
ALTER Table Student MODIFY (name VARCHAR(50));
ALTER Table Student DROP name;
Drop
: db 스키마 제거DROP Table Student
Truncate
: 스키마는 유지하면서 자료만 버림TRUNCATE Table Student
Rename
: 이름 변경RENAME Student TO employee
Comment
: 테이블에 설명 추가Constraint
: 테이블에 제약조건 생성Table의 특정규약을 설정한다 즉 제약조건이다.
1 | CREATE TABLE book ( |
Insert
, Delete
, Select
,Update Table
내부의 data를 바꿀때 사용한다.
Insert
테이블 Data 추가INSERT INTO 테이블이름 (col1, col2) VALUES(“val1”, “val2”);
Delete
테이블 Data 추가DELETE FROM 테이블이름 Where id = 1;
Update
테이블 Data 추가UPDATE 테이블이름 SET 변경내용 Where id = 1;
평균 구하기SELECT AVG(salary) FROM Student;
SELECT 부서명, AVG(salary) FROM 직장; => 오류 발생
SELECT 부서명, AVG(salary) FROM 직장 GROUP BY 부서명
1 | SELECT SUM(col_name) FROM table_name; |
: 구조화된 질의 언어
가장 기본적인 문법
Select
(Table의 원하는 col을 선택하다)
From
(어떠한 Table에서)
Where
(특정 조건)
Student 테이블을 전부다 가져오고싶다.Select*From Student; => *
는 전부를 나타낸다.
Student 테이블중에서 name(col)을 가져오고싶다.Select name From Student;
Student 테이블중에서 name(col)이 Joy 가져오고싶다.Select name From Student Where name=Joy;
둘 이상의 테이블을 합쳐서 하나의 테이블로 만든다.
Cross Join
(Cartasian Product) 모든 가능한 쌍이 나타난다.
Inner Join
조건을 만족하는 tuple만 나타난다.1 | SELECT name, jobname FROM Student Inner Join Job |
Outer Join
조건을 만족하지 않는 tuple도 나타난다. => null로 표기
Left Outer Join => join table의 왼쪽 table 값중 null인 것도 가져온다.
Right Outer Join => join table의 오른쪽 table 값중 null인 것도 가져온다.
Full Outer Join => 양쪽 table 값중 null인 것도 가져온다.
1 | SELECT name, jobname FROM Student Left Outer Join Job |
1 | SELECT name, jobname FROM Student Right Outer Join Job |
1 | SELECT name, jobname FROM Student Full Outer Join Job |
Natural Join
조건을 만족하는 tuple들의 동일한 col이 합쳐져서 나타난다.Self Join
자기 자신과 JoinEntity-Relationship Diagram
mySql에서 자동으로 그려준다.
스터디 공유용 자료입니다.
목차
axios와 비슷한 promise 기반의 HTTP REQUEST API
참고
1 | fetch(url) |
api주소 https://api.github.com/users
A modern JavaScript utility library delivering modularity, performance & extras.
스터디 공유용 자료입니다.
http://slides.com/woongjae/react-router#/ 참고하였습니다.
리액트는 SPA위한 자바스크립트 라이브러리이기 때문에, 클라이언트 사이드 렌더링과 클라이언트 사이드 라우팅이 필요합니다.
자주 사용하는 API를 봅시다.
가장 기본셋팅
BrowserRouter
Link
Route
1 | create-react-app 프로젝트이름 --scripts-version=react-scripts-ts |
react-router-dom을 설치하자.
1 | yarn add react-router-dom |
type definition 추가.
1 | yarn add @types/react-router-dom |
1 | yarn add semantic-ui-react |
css import는 최상위 컴포넌트에서
1 | "allowSyntheticDefaultImports": true |
<BrowserRouter>
1 | import { BrowserRouter as Router, Route, Link} from 'react-router-dom' |
window.history.pushState()
로 동작하는 라우터 (리로드 없이 주소만 갱신하는 함수)<Link>
HTML의 a태그와 유사하다.
1 | <Link to="/" /> |
<Route>
match, location, history
라는 객체를 넘김1 | exact={true} |
<Route>
props 알아보기1 | const Post = (props: RouteComponentProps<{ postId: string }>) => { |
path
에 정의한 것과 매치된 정보를 담고있음
브라우저의 window.location 객체와 비슷함
URL을 다루기 쉽게 쪼개서 가지고 있음
브라우저의 window.history 객체와 비슷함
주소를 임의로 변경하거나 되돌아갈 수 있음
주소를 변경하더라도 SPA 동작방식에 맞게 페이지 일부만 리로드
<Redirect>
1 | if (!window.localStorage.token) { |
withRouter
withRouter HOC를 통해 히스토리 객체의 속성과
Switch
<Route>
를 감싸서 사용첫번째
만 렌더1 | <Switch> |
1 | <Switch> |
NavLink
to
에 지정한 path와 URL이 매칭되는 경우,아직 정리 덜 됨.
정렬할 데이터가 특수한 형태가 아니라면 standard 정렬 알고리즘을 쓰는것이 가장 좋지만, 정렬알고리즘에도 여러가지가 있고 각각의 정렬방법마다 빅오 노테이션이 다르다.
목차
버블정렬은 가장 쉬운 정렬 알고리즘이지만 시간복잡도가 좋은 퍼포먼스를 내지 못해서 실제로는 잘 사용되지 않는다.
시간복잡도는 O(n²)이며 공간복잡도는 하나의 배열만 사용하여 정렬을 진행하기 때문에 O(n)이다.
자신과 다음의 요소를 비교하여 인덱스를 정한다.
선택정렬은 시간복잡도가 O(n²)으로 버블정렬과 정렬하는 알고리즘이 버블정렬과 유사하다.
한번 순회를 하면서 가장 큰 수를 찾아서 배열의 마지막 위치와 교환한다.
삽입정렬은 1부터 n까지 Index를 설정하여 현재위치보다 아래쪽을 순회하며 현재위치의 값을 현재위치보다 아래쪽으로 순회하며 알맞은 위치에 넣어주는 정렬알고리즘이다.
삽입정렬은 이미 정렬이 되어있다면 O(n)의 시간복잡도를 가지게된다. 정렬이 되어있는 경우라면 한번 순회하며 체크만 하기 때문이며 Big-O 시간복잡도는 O(n²)이다.
병합정렬은 정렬할 리스트를 반으로 쪼개나가며 좌측과 우측 리스트를 계속하여 분할해 나간 후 각 리스트내에서 정렬 후 병합(merge) 정렬 후 병합하는 과정을 통해 정렬하는 알고리즘이다.
병합정렬은 가장 많이 쓰이는 정렬 알고리즘 중 하나 이며 시간복잡도는 최소 O(nlogn)을 보장하게 된다.
1 | // 4. 합병정렬 |
전략
특징
재귀적
으로 처리됨Fractal같은 문제라고 생각하면 된다.
구성
Divide
문제를 크기가 작은 동일한 종류의 sub problems로 분할
Conquer
재귀적으로 subproblems
시간복잡도 구성요소
sequence : 연속된 데이터의 집단
MERGE-SORT는 combine하는 함수이다.크게 고려하지 않아도 되지만, 타입캐스팅 방법처럼 계산 후 앞부분이 하나를 더 가져갈지를 판단한다.
타입을 바꿔주는.
퀵정렬은 real-world 데이터에서 빠르다고 알려져 있어 가장 많이 쓰는
정렬알고리즘이다.
퀵정렬은 pivot을 선정하여 pivot을 기준으로 좌측과 우측으로 pivot보다 작은값은 왼쪽 pivot보다 큰값은 오른쪽으로 재배치를 하고 계속하여 분할하여 정렬하는 알고리즘이다.
최악의 경우에는 O(n²)의 비교를 수행하지만 일반적으로 O(nlogn)의 시간복잡도를 가진다.
읽어볼 글
구린게 있으면 그 부분을 바로 잡으세요.
리팩토링을 어떨 때 시작하고 어떨 때 그만둬야 할지 판단하는 일은 리팩토링 기법을 적용하는 방법만큼 중요하다.
구린내의 제왕 중복코드.
똑같은 코드 구조가 두 군데 이상 있을 때는 그 부분을 하나로 통일하면 프로그램이 개선
한 클래스의 두 메서드 안에 같은 코드가 들어있는경우 -> 메서드 추출 기법을 적용해서 겹치는 코드를 빼내어 별도의 메서드로 만들고 그 메서 드를 두 곳에서 호출
수퍼클래스의 두 하위 클래스에 같은 코드가 들어 있는 경우 -> 메서드 추출 기법을 적용해서 중복을 없앤 후 메서드 상향 기법을 적용하면 된다.
위 상황에 코드가 똑같지 않고 비슷하다면 메서드 추출기법을 적용해서 같은 부분과 다른 부분을 분리해야 한다. 그런 다음 경우에 따라 템플릿 메서드 형성 기법을 적용해야 할 수도있다.
두 메서드가 알고리즘만 다르고 기능이 같다면 개발자는 그 두 알고리즘 중에서 더 간단한 것을 택해서 알고리즘 전환 기법을 적용하면 된다.
중복 코드가 메서드 가운데에 있다면 주변 메서드 추출을 적용하면된다.
서로 상관 없는 두 클래스 안에 중복코드가 있을 때 -> 한 클래스 안의 중복 코드를 클래스 추출 이나 모듈 추출 을 적용해 제 3의 클래스나 모듈로 떼어낸 후 그것을 다른 클래스에서 호출하는 방법이 있다. 또는 중복 코드를 빼서 메서드로 만든 후 그 메서드를 두 클래스 중 하나에 넣고 다른클래스에서 그 메서드를 호출하거나 코드를 빼내어 만든 메서드를 제 3의 클래스에 넣고 그걸 두 클래스에서 호출하는 방법이 있다.
최적의 상태로 장수하는 객체 프로그램을 보면 공통적으로 메서드 길이가 짧다.
짧은 메서드를 이해하기 쉽게하려면 메서드 명을 잘 정해야한다. 메섣의 기능을 한눈에 알 수 있는 메서드명을 사용하면 그 메서드안의 코드를 분석하지 않아도된다.
메서드 호출이 원래 코드보다 길어지는 한이 있어도, 메서드 명은 그 코드의 의도를 잘 반영하는 것으로 정해야한다.
메서드명은 기능 수행 방식이 아니라 목적(즉, 기능자체)을 나타내는 이름으로 정한다.
메서드 추출기법을 적용한다.
코드를 여러 덩어리로 분리하려면?
주석을 찾는 것 -> 기능 설명이 주석으로 처리된 코드 구간을 메서드로 만들면 된다. (긴 메서드에서 기능 설명이 주석으로 되어있는 부분)
조건문과 루프도 역시 메서드로 추출
기능이 지나치게 많은 클래스에는 보통 엄청난 수의 인스턴스 변수가 들어있다. 클래스에 인스턴스 변수가 너무 많으면 중복 코드가 반드시 존재하게 마련
매개변수 세트가 길면 서로 일관성이 없어지거나 사용이 불편, 더많은 데이터가 필요해질 때마다 계속 수정해야 한다
즉 매개변수는 객체를 넘기도록 한다. 객체를 넘김으로써 위 문제들이 해결
수정의 산발은 한 클래스가 다양한 원인 때문에 다양한 방식으로 자주 수정될 때 일어난다.
하나의 클래스를 여러 개의 변형 객체로 분리하는것이 좋다. 그러면 각 객체는 한 종류의 수정에 의해서만 변경된다.
하나의 수정으로 여러 클래스가 바뀌게 되는 문제
수정할 부분들을 전부 하나의 클래스 안에 넣어줘야 한다.
메서드가 자신이 속해있는 클래스보다 다른 클래스에서 더 호출이 이루어질 경우 해당 메서드를 더 접근이 많은 클래스로 옮겨줘야 한다.
두 클래스에 들어 있는 인스턴스 변수나 여러 메서드 시그너처(메서드명과 인수들 목록을 메서드 시그너처 라고 부릅니다.)에 들어있는 매개변수 처럼, 동일한 3~4개의 데이터 항목이 여러 위치에 몰려있는 경우
이렇게 몰려있는 데이터 뭉치는 객체로 만들어야한다.
관련된 데이터를 묶지 못하고 흩어놓게 되면, 각각의 데이터에 대한 정보를 외부에 공개해야한다.
함수를 만들때도 각각의 데이터를 파라미터로 넘겨주어야 하기에 파라미터의 갯수가 늘어나게 된다.
기본형만 사용할 바에는 객체를 만들어서(구조화)해서 사용해라
이때는 각각의 관련된 데이터를 하나의 구조체로 묶어 주어야한다.
switch 문의 단점은 반드시 중복이 생긴다는 점이다. 동일한 switch가 다른 곳에서 또 쓰일가능성이 크다
switch 문에 새 코드행을 추가하려면 그렇게 여기저기에 존재하는 switch 문을 전부 찾아서 수정해야한다.
이 문제를 해결할수 있는 방법은 다형성 즉 재정의를 이용하는 것이다.
switch 문을 메서드 추출로 빼낸 후 메서드 이동을 실시해서 그 메서드를 재정의해야 할 클래스에 옮겨 넣으면 된다.
한 클래스의 하위클래스를 만들 때마다 매번 다른 클래스의 하위 클래스도 만들어야 한다.
중복 코드 부분을 제거하려면 보통은 한 상속 계층의 인스턴스가 다른 상속계층의 인스턴스를 참조하게 만들면 된다.
하나의 클래스를 작성할 때마다 유지관리와 이해하기 위한 비용이 추가된다.
비용만큼의 기능을 수행하지 못하는 비효율적인 클래스는 삭제해야한다.
메서드나 클래스가 오직 테스트 케이스에만 사용된다면 구린내를 풍기는 유력한 용의자로 막연한 범용코드를 지목할 수 있다. 이러한 메서드나 클래스를 발견하면 그것과 그것을 실행하는 테스트 케이스는 삭제하자.
객체 안에 인스턴스 변수가 특정 상황에서만 할당되는 경우가 간혹 있다.
이러한 떠돌이 해당 변수들을 사용하는 class를 생성한다
메시지 체인?
클라이언트가 한 객체에 제 2의 객체를 요청하면, 제 2의 객체가 제 3의 객체를 요청하고 …. 연쇄적으로 요청이 발생하는 문제점
어떤 클래스의 인터페이스를 보니 안의 절반도 넘는 메서드가 기능을 다른 클래스에 위임하고 있을경우
클래스 끼리 관계가 지나치게 밀접한 나머지 서로의 private를 알아내느라 과도한 시간낭비
서로 지나지게 친밀한 클래스는 메서드 이동과 필드 이동으로 떼어 낸다.
기능은 같은데 시그너처가 다른 메서드에는 메서드명 변경을 실시해야 한다.
라이브러리 클래스에 넣어야 할 메서드가 두 개 뿐이라면 외래 클래스에 메서드 추가 기법을, 부가 기능이 많을 때는 국소적 상속확장 클래스 사용 기 법을 사용
데이터 클래스(domain)는 필드 캡슐화기법을 실시해야한다
변경되지 않아야 하는 필드에는 쓰기 메서드 제거를 적용
하위클래스가 부모클래스에게 상속받은 메서드나 데이터가 하위클래스에서 더이상 쓰이지 않거나 필요 없게 되었을때.
위 문제의 원인은 잘못된 계층구조
새 대등 클래스를 작서하고 메서드 하향과 필드하향을 실시해서 사용되지 않는 모든 메서드를 그 형제 클래스에 몰아 넣는다.
주석을 넣어야겠다는 생각이 들 땐 먼저 코드를 리팩토링해서 주석을 없앨 수 있게 만들어보자.
주석은 무슨 작업을 해야 좋을지 모를 때만 넣는 것이 좋다.
어떤 코드를 넣은 이유를 메모해 놓을 경우에도 주석을 넣는 것이 적절하다.
레거시 코드의 양이 방대할 경우 부분별로 리팩토링을 진행해야 한다. 이 때, 유의할 점은 정확한 목표를 가져야 한다는 것이다. 대부분의 개발자는 성능 개선에만 초점을 두는데, 이는 또 다른 레거시 코드를 만들어 낼 수 있다. 레거시 코드를 변경하는 목적은 변경 자체가 아니라 변경시키는 행위이다. 따라서 각각의 작업 끝에는 항상 테스트 코드가 있어야 한다. 이 점을 항상 유념하며 리팩토링을 진행해야 한다.
변경시킬 지점을 알기 위해서는 대상 프로그램의 전체적인 아키텍처를 보아야한다. 노트/스케치나 스크래치 리팩토링 기법과 같은 방법을 통해 변경해야 할 지점을 식별하자.
리팩토링이 필요한 부분을 찾았다면 이제 어느 부분에 테스트 루틴을 작성할 것인지 결정해야 한다. 이를 위한 가장 간단한 판단 기준은 모든 메소드에 대해 테스트를 수행하는 것이다. 또한, 각 메소드들이 의존관계를 이루는 묶음끼리도 테스트가 필요한데, 이를 위해 의존관계를 최소화시키는 것이 중요하다.
코드에서의 의존관계는 다른 클래스나 인터페이스에 방향성을 가지고 의지하는 코드를 의미한다. 예를 들어 A 클래스에서 B 클래스에 있는 메서드를 호출하는 상황을 가정해 보자. 이때 A 클래스가 변경되었다고 해서 B 클래스까지 변경될 필요는 없다. 이를 A 클래스가 B 클래스에 의존하고 있다고 말한다.
이러한 의존관계는 상황별 & 종류별로 매우 다양하며 이를 해소하기 위한 방법도 각양각색이다. 기본적으로 의존관계란 코드의 유지 보수성을 떨어트리기 때문에, 의존관계를 최소화시키는 것이 중요하다. 각 상황별 의존관계 해소 방법을 알고 싶다면, 책으로 출간된 마이클 패더스의 Working Effectively with Legacy Code를 읽어보기 바란다.
테스트 루틴을 작성할 때에는 코드의 동작을 이해하는 데 필요하다고 느끼는 만큼의 사례를 작성해야 한다. 기능을 추출하거나 이동시키려 한다면 사례별로 동작들의 존재 여부와 연결을 검증할 수 있는 테스트 루틴을 작성한다. 이동시키고자 하는 코드를 수행하는지와 그 코드가 적절히 연결되었는지를 검증한 후에 변환을 수행하도록 한다.
전체적으로 볼 때 리팩토링은 덩치가 큰 메소드를 작은 단위로 쪼개는 것이다. 이렇게 된다면 코드를 좀 더 이해하기 쉽게 작성할 수 있다. 또한, 재사용성을 높일 수 있으며 시스템 안의 다른 영역들에 있는 로직과의 중복을 제거할 수 있다.
]]>좋은 알고리즘의 필요 요건과, 알고리즘의 실행 속도를 평가하는 방법을 알아본다.
우리는 finite amount of space and time
에 집중해야한다.
알고리즘은 유한한 자원을 가진 환경에서 주어진 문제를 푸는 동작의 모임이다.
적은 시간과 적은 자원(공간)을 이용해 문제를 해결하는 알고리즘이 좋은 알고리즘이다.
+ 웹 브라우저에서 사용할 수 있는 메모리는 일반적인 데스크톱 애플리케이션의 가용 메모리에 비해 매우 적다. 적은 메모리만 할당받는 주된 이유는 웹 페이지에서 실행하는 자바스크립트가 시스템 메모리를 전부 사용해서 운영체제를 다운시키는 일을 방지하기 위함이다.
메모리 제한은 변수 할당 뿐만 아니라 호출스택, 스레드에서 실행할 수 있는 문장수에도 영향을 미친다.
즉! 가능한 최소한의 메모리만 사용해야 페이지의 성능을 올릴 수 있다.
n명의 페이스북 친구를 가진 A와 m명의 페이스북 친구를 가진 B의 공통 친구의 수는
시간복잡도란 알고리즘이 문제를 해결하기 위한 시간(연산)의 횟수
를 말한다.
computational complexity that measures or estimates the time
taken for running an algorism.
Time complexity is commonly estimated by counting the number of elementary operations
performed by the algorism, supposing that an elementary operation takes a fixed amount of time to perform.
알고리즘을 평가하는데 있어 수행시간과 메모리 사용량을 평가기준으로 두는데
수행시간에 해당하는 것이 시간 복잡도
Time Complexity,
메모리 사용량에 해당하는 것이 공간 복잡도
Space Complexity이다.
연산 횟수를 카운팅 할때 3가지 경우가 있다.
평균적인 경우가 가장 이상적으로 보이겠지만 알고리즘이 복잡해 질수록 평균적인 경우는 구하기가 매우 어려워 진다. 그러므로 최악의 경우로 알고리즘의 성능을 파악한다.
즉, 알고리즘의 실행 순서를 따라가며 Elementary Operation이 일어나는 수를 측정한다.
1 | let count = 0; |
주어진 프로그램 2개의 성능 비교 및 분석
C1, C2, C3에 따라서 대소 비교 결과가 다름.
어떤 C1, C2, C3에 대해서도 C1 * n^2 > C3 * n을 만족하는 n은 존재함.
n이 작으면 프로그램 P1의 성능이 더 좋을 수도 있다.
n이 충분히 크면
항상 프로그램 P2의 성능이 좋다. (P1에는 n이 제곱이기 때문에)
작은 경우 모두 성능이 좋으므로 문제될 것은 없다.
따라서 n이 큰 경우의 처리가 중요하다.
Big O가 중요한 이유를 알기 위해서는 Asymptotic Complexity에 대해 알야아한다.
알고리즘의 성능평가는 시간복잡도와 공간복잡도를 계산하고, 적 표기법으로 나타내면 된다.
위 예와 같이 T(n)으로 표현한 함수의 최고차항의 차수
가 빅오가 된다.
빅오의 순서는 아래와 같고 커질수록 좋지 않다.
보통 O(n^2)이상의 복잡도를 가지는 알고리즘은 좋지 않다.
입력의 크기가 충분히 클 때의 시간복잡도
와 공간복잡도
를 분석하는 것.
프로그램 성능이 Asymptotic(점진적인) Complexity
어떠한 문제 해결을 위한 알고리즘의 성능분석을 할 때, 주어지는 데이터의 형태나 실험을 수행하는 환경, 또는 실험에 사용한 시스템의 성능등 다양한 요소에 의해 공평한 결과가 나오기 힘들고 비교 결과가 항상 일정하지 않을 수 있다.
이를 효과적으로 해결하는 방법이 점근적 분석법이다. 점근적 분석법은 각 알고리즘이 주어진 데이터의 크기를 기준으로 수행시간 혹은 사용공간이 얼마나 되는지를 객관적으로 비교할 수 있는 기준을 제시해 준다.
O(빅오), Ω(오메가), Θ(세타)등이 있다. 일반적으로 빅오와 세타표기가 많이 사용된다.
의사(疑似: 비교할 의, 비슷할 사 | Pseudo: 가짜의- ) 코드는 컴퓨터 프로그램이나 알고리즘이 수행해야할 내용을 우리가 사용하는 언어 (한국어 또는 영어 등)로 간략히 서술해 놓은 것을 말합니다. 왜 의사코드를 사용해야 하나요?
의사코드는 코딩 입력을 시작하기 전, 사고를 좀더 명확히 정립하게 만들어주어
프로그램을 설계하는데 도움이 됩니다. 실제 코드 입력을 처음 시작할 때가 제일 힘듭니다! 단순히 소스코드를 입력하는 것보다 함수(function) 프로그램을 만들 때 많은 시간을 낭비할 수 있습니다. 약 10분 정도 각 풀이법의 장점과 단점을 주도면밀하게 살펴보면서 의사코드 작성한다면, 이후 디버그를 수정하고 코드를 재분해 하는데 걸리는 시간을 단축할 수 있습니다.
모델링이라고 생각해보자.
목차
단위테스트는 모듈이나 어플리케이션 안에 있는 개별적인 코드 단위가 예상대로 작동하는지 확인하는 반복적인 행위이다.
프로젝트에 단위 테스트를 적용하는 데에는 “내 코드가 제대로 동작하는지 확인하는 것”이라는 명백한 이유 외에도 몇 가지 장점이 있다.
작게
만든다.많은 일을 하는 테스팅 코드는 어렵다.’
‘많은 일을 하는 디버깅 코드는 어렵다.’
이 두 가지 문제의 해결법은 많은 일을 하지 않도록 코드를 작성하는 것이다. 각각의 함수를 단 한가지만의 일을 하도록 작성해야 한다. 이렇게 하면 단위 테스트로 쉽게 테스트할 수 있다. (하나의 함수에 대해 많은 단위 테스트가 필요하지 않는다.)
내 동료가 메소드를 더 작게 분리해야 하는지에 대해 판단할 때 사용하는 문구가 있다. 만약 코드의 역할을 다른 프로그래머에게 설명할 때 ‘and’라는 단어를 사용했다면 그 메소드는 적어도 하나 이상의 부분으로 나눠야 한다는 것이다. stackoverflow
단위 테스트의 다른 장점은 문제를 빨리 발견하고 변화를 쉽게하며 통합을 간단하게 하고 설계를 개선할 수 있다는 것이다.
여기까지 읽고 나니, 테스트코드를 짜는 것은, 설계도를 만들면서 프로그래밍을 한다고 생각해도 될듯하다. 스케치를하는 느낌! 아키텍처를 짜면서 프로그래밍을 할 수 있다.
단위테스트의 시작은 어렵다. “hot to start unit testing”를 구글에 검색하면 113,000,000의 결과가 나올정도로. 단위테스트를 시작하는 가장 쉬운 방법은 버그를 고치는 것입니다. 그 방법은 아래와 같다.
요구사항이 수시로 변경되고 프로젝트 일정이 눈에 보이기 시작하면 테스트 코드 없이 바로 로직 구현을 하는 경우가 태반이라고 했다. 물론 신속히 개발할 수 있지만, 나중에 유지 보수 때 문제가 발생한다고 한다. 유지보수라고 하지만 새로운 기능을 요구할 때도 있다. 기존 로직에 영향을 주지 않고 코드를 작성해야 하는데 테스트 코드 없이 구현하다 보면 사이드 이펙트가 여기 저기서 터진다. 결국 유지보수기간에 코드에 대한 테스트 코드를 다시 작성하는 사태..
프로그래머 작업 중 가장 많은 시간을 투자하는 일이 유지보수이다. 유지보수하기 좋은 코드를 구현하는 것은 서비스의 성패를 좌우하는 중요한 요소이다. 유지보수하기 좋은 코드를 구현하는 핵심은 클린 코드 구현에 있다.
운영 중 필연적으로 발생하기 마련인 기능 추가, 버그 수정, 레거시 코드 리뷰(이전 개발자들의 유산과도 같은 코드) 및 수정 작업과 같은 변화 자체에 확장성있게 대응하려면 클린 코드에 대한 이해와 작성 능력이 필수. 변화를 피할 수 없으면 제대로 대응하자.
읽기 좋은 클린 코드를 작성함으로서 오는 장점은 개인에게만 있지 않다. 특히 1인 개발이 아닌, 여러 개발자가 함께 참여하는 프로젝트일수록 확장성 있는 코드 작성 능력을 가진 개발자의 기여도는 높을 수 밖에 없다.
Legacy code
RED
: 실패하는 테스트GREEN
: 테스트에 통과하도록 코드를 작성REFACTOR
: 불필요한 코드를 삭제참고한 글에서는 심리적인 안정감을 준다고 한다. 테스트 없이 개발하면 그물망 없는 막타워를 뛰어 내리는 심정이라면서.. 코드 한줄한줄이 부담스럽다고 한다.
생각해보면 이전 프로젝트에서는 테스트코드 없이 작업에 들어갔었고, 기능구현은 됐으나, 내가 보기 싫은 정도의 무자비한 코드들이 나왔다. 그러다보니 리팩토링조차 하지 못하는 상황.. 그런 의미에서 클린코드를 위한 작업이라고 생각하면, 좋을 듯하다.
BDD는 행동 베이스이다.
엔드 유저의 행동을 시나리오로 가져야합니다.
가령 로그인을 예로 BDD를 하려면, 셀레늄으로 실제 브라우저에서 렌더링된 아이디와 패스워드를 입력폼에 넣고 로그인 버튼까지 누르는걸 시뮬레이트해야한다.
Given, When, Then
1 | Scenario: User uses wrong password |
react 테스트때는 Enzyme과 묶어서 Mocha 사용할 예정.
Typescript사용, type definition으로는 mocha, node, express 셋팅, 의존모듈 : mocha, shoudld, supertest, typeScript
실습을 위해 필요한 것과 알야아할 용어
mocha는 node와 브라우저 모두에 적용할 수 있고, TDD, BDD, QUnit, export 스타일 모두 적용할 수 있는 프레임웍이다. assertion문 또한, 취향(?)에 따라 선택하여 적용할 수 있다.
assertion문 expect, should, assert …
1 | res.body.should.be.a.Object(); // res.body는 Object 형태이어야한다. should.be.a |
통합테스트
(api 기능 테스트)에서 사용하는 라이브러리1 | const supertest = require('supertest'); |
서버에서 구현하는 API는 단순히 메모리상의 데이터를 다루는 것만 있는 것은 아닙니다. 사용자 계정 정보 등 영구적으로 저장할 데이터는 데이터베이스에 저장하게 되는데, 서버에 이 정보를 데이터베이스에서 조회한 뒤 API로 응답하는 경우가 빈번합니다.
그럼 유닛 테스트를 위해 데이터베이스에 직접 자료를 넣어야 할까요? 그렇게 할 수도 있겠지만 시간이 많이 걸립니다. 왜냐하면 테스트를 위해 데이테베이스 컨넥션을 생성한 뒤 데이터를 입력하고 조회하는 시간이 상당하기 때문입니다. 게다가 이러한 API가 많아질수록 전체 테스트 시간은 늘어나게 됩니다.
그래서 목(Mock)을 사용해야 합니다. 데이터베이스 역할을 흉내낼 수 있는 가상의 것을 만들수 있습니다.
Sinon.js는 주로 테스트 대상이 의존하는 모듈과 자원의 대역
의 용도로 사용한다. 특정 테스트 프레임워크를 의존하지 않기 때문에 QUnit 이외의 테스트 프레임워크와도 함께 사용할 수 있다. Sinon이라는 이름은 트로이 전쟁에서 활양한 스파이의 이름에서 유래했다.
복잡한 비동기나 동시 다발적인 이벤트 그리고 애니메이션등 작성하기 어려운 테스트 타입
을 Spy, Stub, Mock, FakeTiner, FakeServer 등으로 대체하여 테스트하기 쉽게 만들어 준다.
MOCK작업을 할 수 있게 하는 라이브러리라고 생각하면된다.
MOCK : 데이터 베이스 역할을 흉내내는 가상의 것
실제 객체를 만들기엔 비용과 시간이 많이 들거나 의존성이 길게 걸쳐져 있어 제대로 구현하기 어려울 경우, 가짜 객체를 만들어 사용한다.
JavaScript는 브라우저 환경에 따라, 테스트 결과가 달라지기 때문에, 실제 브라우저에서 테스트를 꼭! 해야만한다. 테스트 러너는 여러 환경에서 동일 테스트를 호출 할 수 있다.
참고링크
‘프론트엔드 개발자를 위한 자바스크립트 프로그래밍’ 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
목차
함수의 재귀 부분은 함수Part 포스팅의 callee의 예시를 보면서 설명했었다. 추가로 스트릭트 모드일 경우에 arguments.callee
에 접근할 수 없으므로 이를 보완하는 방법을 알아본다.
1 | const factorial = (function f(num){ // f()를 생성하여 factorial에 할당. |
f라는 이름은 함수를 다른 변수에 할당하더라도 그대로 유지되므로 재귀 호출은 정확히 실행됨.
클로저란 다른 함수의 스코프에 있는 변수에 접근 가능한 함수이다.(내부함수가 외부함수의 스코프에 접근가능). 즉, 내부함수가 참조하는 외부함수의 지역변수가 외부함수에 의해 내부함수가 반환된 이후에도 life-cycle이 유지되는 것을 의미한다.생성될 당시의 환경을 기억하는 함수를 말한다.
클로저를 잘 이해하기 위해서는 스코프 체인이 어떻게 생성되고 사용되는지 자세히 알아야 한다.
함수에서 변수에 접근할 때마다 스코프 체인에서 해당 이름의 변수를 검색한다. 함수 실행이 끝나면 로컬 활성화 객체는 파괴되고 메모리에는 전역 스코프만 남는다. 하지만 클로저는 외부함수가 실행을 마쳐도 활성화 객체는 내부함수가 파괴될 때가지 메모리에 남는다.
1 | function createComparisonFunction(propertyName){ |
자신을 포함하고 있는 외부함수보다 내부함수가 더 오래 유지되는 경우,
내부함수가 외부함수의 스코프에 접근할 수 있고,
외부함수는 외부함수의 지역변수를 사용하는 내부함수가 소멸될 때까지 소멸되지 못하고 상태가 유지되며
내부함수에 의해서 소멸하게 되는 특성을 클로저라고 부른다.
외부함수의 지역변수를 Free variable(자유변수)이라고 부르는데, 클로저라는 이름은 자유변수에 함수가 닫혀있다(Closed)라는 의미로, 자유변수에 엮여있는 함수라는 뜻이다.
외부함수가 이미 반환되었어도 외부함수 내의 변수는 이를 필요로 하는 내부함수가 하나 이상 존재하는 경우, 계속 유지된다. (내부함수가 외부함수에 있는 변수의 복사본이 아니라 실제변수에 접근한다.)
클로저는 외부함수의 스코프를 보관해야하므로 다른 함수에 비해 메모리를 많이 요구한다. 클로저를 과용하면 메모리 문제가 생길 수 있으니, 반드시 필요할 때만 사용하길 권장한다.
함수 안에 함수를 정의하고 내부에 정의한 함수를 노출시키면, 클로저를 사용할 수 있다. 함수를 노출시키기 위해서는 함수를 반환하거나 다른 함수로 전달하면 됩니다.
1 | function createFunctions(){ |
result 배열에 들어가는 모든 함수가 스코프체인에 createFunctions()
의 활성화객체를 포함하므로, 이들은 모두 같은 변수, i를 참조한다. 때문에 마지막에 할당된 i가 저장이 되는것이다.
이는 for루프의 초기문에 사용된 var키워드 변수의 스코프가 전역이기 때문에 발생하는 현상이므로, ES6의 let
키워드를 이용하여 블록레벨 스코프 개념을 만들면 원하는 결과값이 나오긴한다.
하지만.. 우선 let이 없다는 상황에서 클로저를 사용하여 원하는 결과값을 반환해보자.
1 | function createFunctions(){ |
클로저는 외부함수의 활성화객체 참조를 계속 유지하기 때문에 참조카운트가 줄지 않는다. (가비지컬렉션이 잡지 치우지 못한다.) 필요하다면 클로저를 갖고 있는 변수에 null을 할당하여 참조를 끊어야한다.
리액트 공식 사이트로 들어가면 부제목으로 이런 글이 있다.A JavaScript library for building user interfaces
UI 작업을 위한 자바스크립트 라이브러리!
사용자가 서비스를 접하면서 만나게되는 여러 상황에 빠르게 대응할 수 있고, 다양한 UI 트리거를 빠르게 만들 수 있도록 나온 라이브러리가 아닌가 한다. 그만큼 개발에도 사용자 경험을 많이 신경쓰고 있다는 점에서, UI와 인터렉션은 정말 화두 오브 화두. 상태관리를 손쉽게 할 수 있다는 점때문에 개발자가 UX를 고민할 시간이 더 생긴다는 점에서 리액트를 선호한다. 최근에는 앵귤러를 입문하고 있는데, 비슷한 패턴으로 상태관리를 한다고 느껴지긴했지만, 아직 어려운 개념들이 많고.. 그래서 아직 리액트와의 차이점은 잘 모르겠다.
목차
front 영역을 제어하기 위해서는 자바스크립트로 DOM을 컨트롤 하면 된다. 이는 다양한 인터렉션 기능들을 구현할 수 있게 해주지만 이 DOM이라는 것을 조작하기에는 여간 까다로운게 아니다.(바닐라로 간단 기능을 짜본사람은 무슨 느낌인지..) 이런 까다로운 DOM을 쉽고 효율적으로 다루기 위해 Jquery 라이브러리가 나왔다. But, 제이커리는 여러가지 이슈를 갖고 있었다.
SPA 개발을 위한 구글의 오픈소스 자바스크립트 프레임워크인 Angular가 등장하면서 구조화된 프론트엔드 환경을 제시했다. 이런 상황에서 Facebook에서 React가 등장하게 된다. React는 에어비엔비, 넷플릭스, 드랍박스, 트위터 등에서 사용하고 있다. 리엑트는 자바스크립트 라이브러리이며, 라우터와 같이 웹을 만들 때 필요한 도구들을 포함되어 있지 않다. (앵귤러는 포함되어있음) 필요한 도구들이 없는 대신? 가볍다. 그리고 빠르게 배울수 있다는 점!
React 공식 사이트에서 말하는 특징
React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.
Declarative views make your code more predictable and easier to debug.
직관적
리액트는 인터렉티브 UI를 어려움없이 만들 수 있습니다. 당신의 어플리케이션의 각각의 상태를 위해 간단한 view들을 디자인을 해보십시요. 리액트는 데이터가 변할때 해당 컴포넌트를 효과적으로 업데이트하고 렌더링 할 수 있습니다. 직관적인 view들은 디버깅하기 더 쉽게, 더 잘 예측할 수 있도록 해줍니다!
Build encapsulated components that manage their own state, then compose them to make complex UIs.
Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM.
컴포넌트 단위.
자체 상태를 관리하는 캡슐화된 컴포넌트를 만들어서 복잡한 UI를 만들 수 있도록 구성해보세요. 템플릿 대신 자바스크립트로 작성된 컴포넌트 로직을 통해 여러분은 풍부한 데이터를 쉽게 전달하고, DOM에서 상태를 유지할 수 있습니다.
We don’t make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code.
React can also render on the server using Node and power mobile apps using React Native.
한번배우고, 어디서나 쓰십쇼!우리는 여러분의 기술 스택의 나머지 부분에 대해서 가정하지 않았으므로 여러분은 기존 코드를 다시 작성하지 않고, React에서 새로운 기능을 개발할 수 있습니다. React는 React Native를 사용하여 Node나 모바일 앱을 사용하여 서버에서 렌더링할 수 있습니다.
component는 UI를 구성하는 개별적은 View 단위이다. 이 단위들이 레고 블럭처럼 조합되어서 최종 결과물을 만들어낸다. 이는 앵귤러도 같은 개념이다. Component의 강력한 특징은 재사용이 가능하다. 틀을 만들어 놓고 여러 컴포넌트로 갖고가서 사용이 가능하다는 것.
리덕스 창시자 Dan Abramov는 React의 목표가 성능보다는 유지가능한 앱을 만드는 것!이라고 설명했다고 한다.
JSX는 React에서 사용하기 위해서 새로 만들어진 자바스크립트 문법이다.
React는 작성한 코드를 컴파일하는 과정을 꼭 거쳐야한다. 때문에 리액트에서는 Babel을 사용하고 있다.
1 | class HelloMessage extends React.Component { |
return 내부의 형태와 ReactDom.render의 첫번째 인자는 JSX문법이다. 이를 자바스크립트로 컴파일을 하기위해 Babel을 사용하는 것이다. 자바스크립트로 컴파일 후의 모습은 아래와 같다.
1 | class HelloMessage extends React.Component { |
React는 Babel과 같은 트랜스파일러를 꼭 사용해야하기 때문에 Webpack등을 사용해야하는데, 왜 구지 이런 셋팅을 하면서까지 JSX를 사용하는 걸까. 위처럼 작성해도 되지만, 공식사이트에서 말한 첫번째 특징인 직관적인(Declarative) 개발을 할 수 있도록 하기 위해 JSX를 사용한다. JSX를 보면 html마크업과 거의 같다고 볼 수 있다. 어떤 결과물이 나올지 이해가 된 상태에서 개발하기 때문에 예측가능 개발을 할 수 있도록 해주며, 개발의 피로도를 상당히 줄여준다.
DOM은 웹의 핵심으로, 말 그대로 브라우저가 화면을 그리기 위한 정보가 담겨있는 문서이다. 이 DOM을 다루는 것이 힘들다는 것은.. 바닐라로 짜보면 알 수 있다. 정확히는 DOM 조작이 전체 동작을 비효율적으로 만드는게 아니라, 그 이후에 일어나는 일 때문에 작업이 더뎌지는 거라고 한다. DOM에 변화가 생기면, 렌더트리를 재생성하고(모든 요소의 스타일이 다시 계산된다.) 레이아웃을 만들고, 페인팅을 하는 과정을 반복한다. 그만큼 DOM을 쉽게 다룰 수 있는 부분은 개발자들의 숙제였고, 그러던 중에 Jquery가 탄생하게 된것이다.
1 | class HelloMessage extends React.Component { |
React 컴포넌트는 render를 다시 호출하여 새로운 결과 값을 return한다. 그런데 이 리턴값은 바로 DOM에 반영되지 않는다! 즉 렌더링이 되지 않는다는 말인데, react는 return값을 갖고 새로운 Virtual DOM을 만든다.. 그리고, 현재 브라우저에 보여지고 있는 진짜 DOM과 비교하여 어떤 부분이 달라졌는지 찾아낸다. 달리진 부분을 발견하면 그 부분만! 바뀐 그 부분만 진짜 DOM에 반영한다. 그리고 브라우저는 이 DOM을 해석하고 유저에게 새로운 화면을 그려준다. 즉, 브라우저 내에서 발생하는 연산의 양을 줄이면서 실제 DOM을 조작하는 것보다 성능이 개선이 된다.
가상돔을 만든 이유는, 직접 DOM을 조작하는 리소스가 많으 드는 행위를 하지않고, DOM을 조작하는 과정을 최적화시켜주고, 컴포넌트 단위로 묶어서 관리할 수 있도록 해준다. 컴포넌트 단위의 개발을 구현하기 위해 보다 효율적인 DOM 조작 방식을 도입한 것이다.
‘프론트엔드 개발자를 위한 자바스크립트 프로그래밍’ 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
이 주제는 조금 더 공부를 해야할 듯 하다.
목차
객체지향언어는 일반적으로 클래스를 통해 같은 프로퍼티와 메서드를 가지는 객체르 여러 개 만든다는 특징이 있다. ECMAScript에는 클래스라는 개념이 없으며 이에 따라 ECMAScript의 객체는 다른 클래스 기반 언어와 다르다. (ES6에는 class라는 개념이 도입되었다.)
ECMAScript에서 객체는 순서가 없는 값의 배열이다. 각 프로퍼티와 메서드는 이름으로 구별하며 값에 대응한다. 객체는 이름-값 쌍의 그룹이며 각 값은 데이터나 함수가 될 수 있다.
객체 리터럴 방식으로 객체를 생성할 때 프로퍼티와 메서드를 생성할 수 있다. 이러한 프로퍼티는 모두 자바스크립트에서 프로퍼티의 행동을 정의하는 특징
에 따라 생성된다.
이들 속성이 자바스크립트 엔진 내부에서 구현하는 것으로 정의했고, 이들 송성을 자바스크립트에서 직접적으로 접근할 수 있는 방법은 없다.
이들 속성은 [[Enumerable]]
처럼 속성 이름을 대괄호로 감싸서 내부 속성임을 나타낸다.
데이터 프로퍼티와 접근자 프로퍼티 두가지 타입이 있다.
데이터 값에 대한 단 하나의 위치를 포함하여 이 위치에서 값을 읽고 쓴다.(무슨말이지?)
[[Configurable]]
프로퍼티가 delete를 통해 삭제하거나, 속성을 바꾸거나 접근자 프로퍼티로 변활할 수 있음을 나타낸다.
객체에서 직접 정의한 모든 프로퍼티에서 이 속성은 기본적으로 true
[[Enumerable]]
for-in
루프에서 해당 프로퍼티를 반환함을 나타낸다.
기본은 true
[[Writable]]
프로퍼티 값을 바꿀 수 있음을 나타낸다.
기본은 true
[[Value]]
프로퍼티의 실제 데이터 값을 포함한다. 프로퍼티의 값을 읽는 위치이고, 새로운 값을 쓰는 위치.
기본값은 undefined
프로퍼티를 선언만 하고 값을 할당하지 않으면
undefined
1 | const person ={ |
여기서 “Nicholas”가 [[Value]] 데이터 프로퍼티에 저장된다는 말이다.
Object.defineProperty()
메서드를 사용하면 된다.
1 | Object.defineProperty(프로퍼티를 추가하거나 수정할 객체, 프로퍼티 이름, 서술자 객체) |
해당 속성에 대한 특성을 의미.
내부 속성 이름과 같다. 서술자 객체에는 configurable
, enumerable
, writable
, value
4가지 프로퍼티가 있다.
1 | const person = {}; |
데이터 값이 들어있지 않고, getter
함수와 setter
함수로 구성된다. (옵셔널)
접근자 프로퍼티를 읽을 때는 getter함수가 호출
접근자 프로퍼티의 4가지 속성
[[Configurable]]
프로퍼티가 delete를 통해 삭제하거나, 속성을 바꾸거나 접근자 프로퍼티로 변활할 수 있음을 나타낸다.
기본은 true
[[Enumerable]]
for-in
루프에서 해당 프로퍼티를 반환함을 나타낸다.
기본은 true
1 | var person = { |
[[Get]]
프로퍼티를 읽을 때 호출할 함수.
기본은 undefined
[[Set]]
프로퍼티를 바꿀 때 호출할 함수.
기본은 undefined
1 | const book = { |
setter의 경우는 프로퍼티의 값을 바꿨을 때 해당 프로퍼티만 바뀌는 게 아니라 부수적인 절차가 필요한 경우에 사용한다.
getter만 셋팅할 경우 읽기전용
setter만 셋팅될 경우 undefined
여러개의 프로퍼티를 동시에 수정해야할 경우 Object.defineProperties()
configurable의 기본값은 true이지만, defineProperties나 defineProperty은 공통적으로 호출만 되면 true로 재지정하지 않는 이상 false가 된다.
1 | Object.getOwnPropertyDescriptor(읽어올 프로퍼티가 포함된 객체, 서술자를 가져올 프로퍼티 이름) |
원하는 프로퍼티의 서술자 프로퍼티를 읽을 수 있다.
모든 객체에서 사용가능하며, DOM이나 BOM 객체에서도 가능하다.
1 | const book = {}; |
‘프론트엔드 개발자를 위한 자바스크립트 프로그래밍’ 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
목차
함수 내부에는 객체들이 있다.
요약
arguments
함수에 전달된 파라미터를 모두 포함하는 유사배열객체this
함수의 호출패턴에 따라 값이 달라진다. caller
해당 함수를 호출한 함수를 참조하는 값을 갖고있다. 전역함수에서는 null. 재귀함수를 사용할 때 사용가능.length
arguments의 배열 길이. (파라미터의 갯수)name
함수의 이름__proto__
모든 객체가 갖고 있는 프로퍼티. [[Prototype]] 이며, 브라우저마다 다르게 명시한다. 해당 객체의 프로토타입을 가리키는 참조값을 갖고있다.prototype
함수 객체가 생성자로 사용될 때 이 함수를 통해 생성된 객체의 부모 역할을 하는 객체를 가리킨다.apply
함수를 호출하면서 해당함수의 this를 호출한 함수로 넘기는 역할을 한다. call
apply와 같은 개념이며, apply와 다른 점은 parmeter를 각각 넘기는 스타일이다.bind
bind() 메소드는 호출될 때 그 this 키워드를 제공된 값으로 설정하고 새로운 함수가 호출될 때 제공되는 주어진 순서의 선행 인수가 있는 새로운 함수를 생성한다.arguments
순회가능한(iterable) 유사배열객체이며, 함수에 전달된 파라미터를 모두 포함한다.
arguments 프로퍼티는 arguments 객체를 값으로 가지며, 함수 내부에서 지역변수처럼 사용된다. 즉, 외부에서는 호출할 수 없다.
arguments 객체에는callee
, length
, Symbol
프로퍼티가 존재한다.callee
프로퍼티는 arguments 객체의 소유자인 함수를/ 가리키는 포인터이다.
1 | function factorial(num){ |
1 | // 함수 이름에 의존하는 약점을 callee로 보완 |
this
caller
caller 프로퍼티에는 해당 함수를 호출한 함수에 대한 참조를 저장하며, 전역 스코프에서 호출했다면 null
이 저장된다.
함수에서 사용된 this는 실행된 객체를 가리키거나 상위 컨텍스트인 window를 가리킨다.
this를 조작해서 다를 객체를 지정하려면? apply나 call을 사용하면 된다.
apply
메서드소유자인 함수를 호출하면서 this를 파라미터로 넘기는데, 결론적으로는 함수 내부에서 this객체의 값을 바꾸는 것이나 마찬가지이다. 매개변수로는 소유자함수에 넘길 this와 매개변수 배열을 (Array의 인스턴스 혹은 arguments)를 받는다.
1 | function sum(num1, num2){ |
call
apply와 같은데, 두번째 파라미터를 array형태가 아니라, 각각 나열해야한다.
1 | function sum(num1, num2){ |
bind
새 함수 인스턴스를 만드는데 그 this는 bind()에 전달된 값이다.
1 | window.color= "red"; |
__proto__
프로퍼티ECMAScript spec에서는 모든 객체
는 자신의 프로토타입을 가리키는 [[Prototype]]
이라는 숨겨진 프로퍼티를 가진다라고 되어있다. [[Prototype]]
와 __proto__
는 같은 개념이다.
prototype
프로퍼티함수 객체만이 갖고 있는 프로퍼티로, 자바스크립트 객체지향의 근간이다. __proto__
와 다르다.
constructor
프로퍼티를 가지는 객체를 가리킨다. 이 constructor 프로퍼티는 함수 객체 자신을 가리킨다.함수의 정의와 동시에 실행되는 함수를 즉시호출함수라고 한다. 최초 한번만 호출되며 다시 호출할 수는 없다. 이러한 특징을 이용하여 최초 한번만 실행이 필요한 초기화 처리등에 사용할 수 있다.
react에서 componentwillmount의 개념
즉시실행함수 내에 처리 로직을 모아 두면 혹시 있을 수도 있는 변수명 충돌을 방지할 수 있어 이를 위한 목적으로 사용되기도 한다.
1 | // 기명 즉시실행함수(named immediately-invoked function expression) |
함수 내부에 정의된 함수를 내부함수라 한다.
내부함수는 부모함수의 변수에 접근할 수 있지만, 부모함수는 자식함수의 변수에 접근할 수 없다.
콜백함수는 함수를 명시적으로 호출하는 방식이 아니라 특정 이벤트가 발생했을 때 시스템에 의해 호출되는 함수를 말한다. 보통 이벤트 핸들러 처리때, 비동기식 처리모델에 사용된다. 옵저버(Observer) 디자인 패턴에서 나온 개념이다.
1 | setTimeout(function () { |
비동기식 처리 모델이란 처리가 종료하면 호출될 함수(콜백함수)를 미리 매개변수에 전달하고 처리가 종료하면 콜백함수를 호출하는 것이다.
콜백함수는 콜백 큐에 들어가 있다가 해당 이벤트가 발생하면 호출된다.
콜백 함수는 클로저이므로 콜백 큐에 단독으로 존재하다가 호출되어도 콜백함수를 전달받은 함수의 변수에 접근할 수 있다. (참고)
그런데 왜 이름이 callback 일까?
설명1 -
선언된 함수를 이용하는 것을 호출 (call) 한다고 표현 한다. 콜백 함수는 운영체제(혹은 웹)에 의해 호출되는 응용 프로그램의 함수라 할 수 있다. 호출되는 방향이 정상적인 호출과 달리 반대된다는 의미에서 콜백이라고 한다. 정상적인 함수 호출 방법과는 다르게 운영체제 ( 시스템 ) 측에서 이벤트를 발생시켜서 이에 대한 처리를 해달라고 요청해 오는 과정이 있기 때문에 이와 같은 이름이 붙여졌다고 할 수 있다.
설명2 -
콜백함수란 API 의 반대개념이라고 볼 수 있습니다.
또한 말그대로 콜백! CallBack > 반대로 부른다고 해석할 수 있지요.
우리는 작성하는 일반 코드내에서
보통 API나 SDK에서 제공해주는 함수(Function)들을 호출(Call)하여 사용하곤 한다.
이런 방식의 경우, 어떤 이벤트를 제어하기 위해서는 별도의 쓰레드를 생성하여 무한루프로 실시간 검사하는 꽤나 무겁고 살짝 무식한 프로그램들을 만들어야한다.
보통 이럴때, 사용하는 것이 콜백(CallBack) 함수.
물론 시스템상 CallBack함수를 만들어 등록하는 방식이 제공되어야 한다.
Windows 프로그램상에서 On??Event()를 통해 등록하는 방식이나, 안드로이드 상에서 Listener를 등록하는 방식이 이와 같다.
콜백함수라는 말 그대로 일반 Call의 반대 방향을 말한다.
통상적으로 쓰듯이 우리가 시스템상의 함수를 Call하는 것이 아니라, 시스템에서 우리가 만들고 등록한 함수를 Call하는 방식.
‘프론트엔드 개발자를 위한 자바스크립트 프로그래밍’ 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
목차
함수는 객체이다. 모든 함수는 Function타입의 인스턴스이며, 프로퍼티와 메서드가 있다.
함수란 어떤 특정 작업을 수행하기 위해 필요한 일련의 구문들을 그룹화하기 위한 개념이다.
함수 선언식
1 | function sum (num1, num2) { |
함수 표현식 Function expression
1 | const sum = function(num1, num2){ |
익명 함수
로 간주한다. Function 생성자 사용
1 | const sum = new Function('num1','num2','return num1 + num2') |
괄호를 쓰지않는 sum
괄호를 쓰지 않고 함수 이름만 쓰면 함수를 실행하지 않고 함수를 가리키는 포인터에 접근(만)하는 것이다.
자바스크립트 엔진이 실행 컨텍스트에 데이터를 불러올 때 중요한 차이가 하나 있다.
함수 선언은 어떤 코드도 실행하기 전에 이미 모든 실행 컨텍스트에서 접근하고 실행할 수 있지만
함수 표현식은 코드 실행이 해당 줄까지 진행하기 전에는 사용할 수 없다.
실행 컨텍스트와 같이 생각해보자!자바스크립트 엔진은 코드를 평가할 때 제일 먼저 함수 선언을 찾은 다음 이들을 맨 위로 올린다 (함수 호이스팅). 함수 표현식
은 변수에 함수가 할당된 개념이기 때문에, 해당 변수에 값(함수)이 들어오기 전까지는 undefined
로만 선언되어있는 상태이다.(변수 호이스팅)
1 | alert(sum(10,10)); |
즉, 위 코드를 보면 에러가 나는데, sum은 컨텍스트에 있지만 매개변수를 넘길 수 있는 형태가 아니기 때문에(2번째 줄 오기 전까지는 undefined
) 해당 코드까지 실행하기 전에는 unexpected identifier
에러를 낸다.
(예기치 못한 식별자 = sum(10,10)
을 보고 함수형태의 식별자 sum을 기대하고 찾았는데, 함수형태가 아니라서)
JavaScript : The Good Parts의 저자이며 자바스크립트의 권위자인 더글러스 크락포드(Douglas Crockford)는 이와 같은 문제 때문에 함수표현식만을 사용할 것을 권고하고 있다.
함수 호이스팅이 함수 호출 전 반드시 함수를 선언하여야 한다는 규칙을 무시하므로 1. 코드의 구조를 엉성하게 만들 수 있다고 지적한다.
또한 함수선언식으로 함수를 정의하면 사용하기에 쉽지만 대규모 애플리케이션을 개발하는 경우 2. 인터프리터가 너무 많은 코드를 변수 객체(VO)에 저장하므로 애플리케이션의 응답속도는 현저히 떨어질 수 있으므로 주의해야 할 필요가 있다.
자바스크립트 함수는 일급 객체이다.
일급객체란
프로그래밍 언어의 기본적 조작을 제한없이 사용할 수 있는 대상을 의미한다.
일급객체일 경우 아래와 같은 특징을 갖는다.
함수와 다른 객체를 구분 짓는 특징은 호출할 수 있다는 것이다.
1 | // sample example |
예시2_sort의 createComparisonFunction함수
1 | // sort |
sort(compareFunction)
compareFunction이 제공되지 않으면 요소를 문자열(toString)로 변환하고 유니 코드 코드 포인트 순서로 문자열을 비교하여 정렬됩니다. 예를 들어 “바나나”는 “체리”앞에옵니다. 숫자 정렬에서는 9가 80보다 앞에 오지만 숫자는 문자열로 변환되기 때문에 “80”은 유니 코드 순서에서 “9”앞에옵니다.
문자열 대신 숫자일 경우 value1과 value2를 빼는방법으로 색인을 반환한다.
1 | const numbers = [4, 2, 5, 1, 3]; |
프론트엔드 개발자를 위한 자바스크립트 프로그래밍 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
실행 컨텍스트(Execution Context)는 scope, hoisting, this, function, closure 등의 동작원리를 담고 있는 자바스크립트의 핵심원리이다. ECMAScript 스펙에 따르면 실행 컨텍스트를 실행 가능한 코드를 형상화하고 구분하는 추상적인 개념이라고 정의한다. 즉, 실행 컨텍스트는 실행 가능한 코드가 실행되는 환경
이라고 말할 수 있다.
실행 가능한 코드란
일반적으로는 전역코드와 함수코드.
자바스크립트 엔진은 코드를 실행하기 위해 실행에 필요한 여러가지 정보를 알고 있어야 한다.
자바스크립트 엔진은 실행 컨텍스트를 물리적 객체의 형태로 관리한다.
객체의 형태를 가지며 아래의 3가지 프로퍼티를 소유한다.
변수나 함수의 실행 컨텍스트는 다른 데이터에 접근할 수 있는지, 어떻게 행동하는지를 규정합니다. 각 실행 컨텍스트에는 변수객체(variable object:VO)가 연결되어 있으며, 해당 컨텍스트에서 정의된 모든 변수
와 함수
는 이 객체에 존재한다. 코드로는 접근할 수 없다.
Variable Object는 실행 컨텍스트의 프로퍼티이기 때문에 값을 갖는데, 이 값은 다른 객체를 가리킨다.
전역 컨텍스트와 함수 컨텍스트가 가리키는 객체는 다르다. 함수에만 파라미터가 존재한다.
전역 컨텍스트인 경우
Variable Object는 전역 변수, 전역 함수 등을 포함하는 전역 객체(Global Object/GO)를 가리킨다. 전역변수와 전역함수는 전역 객체의 프로퍼티이다.
전역 컨텍스트란
가장 바깥쪽에 존재하는 실행 컨텍스트이다.
ECMAScript를 구현한 환경에 따라 이 컨텍스트를 부르는 이름이 다르다.
window
전역컨텍스트는 애플리케이션이 종료될 때, 웹페이지를 나가거나 브라우저를 닫을 때까지 유지된다.
함수 컨텍스트인 경우
Variable Object는 Activation Object(AO/활성객체)를 가리키며 arguments object가 추가된다.
arguments object 매개변수와 인수들의 정보를 배열의 형태로 담고 있는 객체이다.
(이전 글에서 함수의 매개변수로 값이 전달될 때 arguments object에 들어간다고 했다. 전달한 값이 argument라고 생각하면 된다. arguments object: 함수 호출 시 전달된 인수들의 정보를 담고 있는 유사배열객체.)
실행컨텍스트 스택
1 | var x = 'xxx'; |
스코프 체인은 일종의 리스트로서 중첩된 함수의 스코프의 레퍼런스를 차례로 저장하고 있는 개념이다.
즉, 현재 실행컨텍스트의 활성객체(AO)를 선두로하여 순차적으로 상위 컨텍스트의 AO를 가리키며 마지막 리스트는 전역 객체를 가리킨다.
스코프 체인의 목적은 실행 컨텍스트가 접근할 수 있는 모든 변수와 함수에 순서
를 정의하는 것.
이것이 스코프 체인이라고 불리는 이유이다.
이와 같이 순차적으로 스코프 체인에서 변수를 검색하는데 결국 검색에 실패하면 정의되지 않은 변수에 접근하는 것으로 판단하여 Reference 에러를 발생시킨다.
스코프 체인은 [[scope]]
프로퍼티로 참조할 수 있다.
this 프로퍼티에는 this 값이 할당된다. this에 할당되는 값은 함수 호출 패턴에 의해 결정되는데, 이는 Function 글에서 자세히 다루겠다.
1 | var x = 'xxx';` |
프론트엔드 개발자를 위한 자바스크립트 프로그래밍 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
요약
가비지 콜렉션은 더 이상 사용하지 않는 메모리를 회수하는 역할을 한다. 메모리를 회수하기 전 사용하지 않는 변수를 체킹해야 하는데 이때 표시하고 지우기
방법과 참조 카운팅
이 있다. 표시하고 지우기 방법
은 처음 컨텍스트의 모든 변수에 마킹을 한 후, 값이 할당되어있거나 참조되어있는 변수의 마킹을 지운다. 지웠음에도 마킹이 남아있는 변수를 회수하는 방식이다. 참조 카운팅
은 참조 카운트가 0인 변수를 회수하는 방식인데 순환참조의 카운팅 한계가 있기 때문에 주로 표시하고 지우기 방법을 사용한다. 가비지 콜렉터 사이클이 도는 것은 상당한 비용이 발생한다. 메모리 누수 관리를 위해서는 사용하지 않는 변수나 객체는 모두 null로 재할당하여 가비지 컬렉터가 다음 사이클 때 회수하도록 하는 방법, 크롬 개발자도구의 퍼포먼스 탭에서 확인하는 방법 등이 있다.
자바스크립트는 인터프리터 언어이다.
(인터프리터 언어란 목적 파일 산출과정이 없이 실행과 동시에 줄 단위로 번역이 된고, 저용량 소스에 적합하다. 코드가 실행되는 시점이 런타임이다. 인터프리터와 컴파일러의 차이점)
고급 언어 인터프리터는 가비지 콜렉터 라는 소프트웨어를 가지고 있다.
가비지 컬렉터(Garbage Collector)란 메모리 할당을 추적하고 할당된 메모리가 더 이상 필요 없어졌을 때 해체하는 작업이다.
이 프로세스는 주기적으로 실행되는데 코드 실행 중에 특정 시점에서 메모리를 회수하도록 지정할 수도 있다. C나 C++같은 언어에서는 메모리 추적이 매우 중요하기 때문에 메모리 관리가 힘들지만, 자바스크립트는 필요한 메모리를 자동으로 할당하고 더 이상 사용하지 않는 메모리는 자동으로 회수하므로 개발자가 직접 메모리를 관리하지 않아도 된다.
가비지 컬렉터는 항상 필요없어진 메모리만을 해제하지만, 모든 필요없어진 메모리를 해제하는 건 아니다. 즉, ‘더 이상 필요없는 모든 메모리’가 아니라 ‘더 이상 필요 없는 몇몇 메모리’를 찾아낸다. 이는 가비지 콜렉션 알고리즘의 한계점이 있기 때문이다.
무튼, 어떤 변수가 더 이상 사용되지 않는지, 사용될 가능성이 있는 변수는 무엇인지 추적해야 메모리 회수 대상을 정할 수 있다. 식별 기준은 2가지이다.
가장 널리 쓰이는 컬렉션 방법이다.
변수가 특정 컨텍스트 안에서 사용할 것으로 정의되면 그 변수는 그 컨텍스트 안에 있는 것으로 표시된다. 표시한는 구체적인 방법은 알 필요는 없다..
GC가 작동하면
가비지 컬렉터는 ‘메모리 청소’를 실행해 표시가 남아 있는 값을 모두 파괴하고 메모리를 회수한다.
각 값이 얼마나 많이 참조 되었는지 추적한다.
순환 참조 문제
이 알고리즘은 두 object가 서로를 참조하면 문제가 발생한다.
1 | function problem(){ |
위의 코드를 보면 새로운 객체가 생성되면서 참조 카운트가 1이되고,
서로 참조하게 되면서 참조카운트가 2가 된다.
이 상태에서 스코프를 벗어나게 되면, 해당 변수는 사용되지 않는데, 벗어났음에도 카운트가 0이 아니기 때문에 GC가 컬렉션을 하지 않게 된다. 이는 곧 메모리 낭비로 이어진다.
이때는 강제로 null을 항당해서 참조했던 값으로의 연결을 끊어줘야한다.
그래서 대부분의 브라우저에서는 표시하고 지우기 방법을 쓴다.
GC는 주기적으로 실행되며 메모리 내에 할당된 변수가 많다면 상당한 비용이 드는 작업이므로 GC를 실행하는 타이밍이 중요하다. 익스플로러는 가비지 컬렉터를 너무 자주 실행하여 성능 문제를 일으키는 것으로 악명이 놓다.
웹 브라우저에서 사용할 수 있는 메모리는 일반적인 데스크톱 애플리케이션의 가용 메모리에 비해 매우 적다. 적은 메모리만 할당받는 주된 이유는 웹 페이지에서 실행하는 자바스크립트가 시스템 메모리를 전부 사용해서 운영체제를 다운시키는 일을 방지하기 위함이다.
메모리 제한은 변수 할당 뿐만 아니라 호출스택, 스레드에서 실행할 수 있는 문장수에도 영향을 미친다.
즉! 가능한 최소한의 메모리만 사용해야 페이지의 성능을 올릴 수 있다.
필요 없어진 데이터에는 null
을 할당하여 참조를 제거(dereference)하는 편이 좋다. 이론상은 그렇지만, 실제로는 많이 사용하지 않는다. 참조를 하고 있는지에 대해서 개발자가 판단하기가 어렵기 때문에 오히려 전체 흐름을 망가뜨리는 행위가 될 수 있다. 우리도 모르게 어디선가 side effect가 발생할 수도있고, 복잡성이 증가한다.(면접 때 면접관님께서 정정해주셨다!)
수동으로 참조 제거해야 할 대상은 주로 전역변수
및 전역 객체의 프로퍼티
이다.
(지역변수는 컨텍스트를 빠져나가는 순간 자동으로 참조가 제거된다.)
참조 제거의 요점은 값의 컨텍스트를 없애서 다음에 가비지콜렉션을 실행할 때 해당 메모리를 회수하도록 하는 것이다.
사용하지 않은 객체, 변수는 모두 null 로 초기화
이벤트 핸들러를 바인딩 했다면, 모두 언바인딩
DOM 을 동적으로 생성했다면, 불필요한 객체, 속성(값)을 DOM 에 삽입하지 말자.
크롬 개발자도구의 Performace탭에서 timeline확인해보자.
V8은 객체가 사용하다가 더 이상 필요 없게 된 메모리를 가비지 콜렉션(garbage collection)이라고 알려진 작업을 통해서 다시 찾아온다. 빠른 객체 할당을 보장하고, 가비지 콜렉션으로 인한 프로그램 정지 시간을 단축시키며, 메모리 파편화를 제거하기 위해서 stop-the-world 방식의 세대적이고, 정확한 가비지 콜렉터(garbage collector)를 채택하고 있다.
이것은 다음을 의미한다.
V8에서 객체의 heap은 2개의 부분으로 나누어져 있다. 새로 객체가 생성되는 영역과 가비지 콜렉션 사이클이 진행되는 동안에 살아남은 객체가 있는 영역. 객체가 가비지 콜렉션으로 들어가면 V8은 객체의 포인터를 갱신한다.
변수를 생성하는 것 자체가 메모리를 사용하는 것인데, 이를 회수하고 관리하는 가비지컬렉션이 있다는 것에 흥미로웠다.
메모리 누수를 막아서 최소한의 메모리 사용으로 페이지 성능을 향상하는 것이 목적이지만, 사이클이 너무 많이 실행되면 이것 또한 자원낭비.
변수의 할당의 최소화하고, 코드 재사용성을 높이고, 전역변수나 전역객체의 프로퍼티가 존재한다면 마지막에 null을 할당해보자.
프론트엔드 개발자를 위한 자바스크립트 프로그래밍 책을 참고하여 정리합니다. 오류가 있다면 언제든지 댓글 남겨주세요.
까묵지말자
Call-by-value, Call-by-reference
변수는 위치(주소)를 기억하는 저장소이다. (포인터의 개념)
위치란 메모리 상의 주소(address)를 의미한다. 즉, 메모리 주소에 접근하기 위해 사람이 이해할 수 있는 언어로 지정한 식별자이다.
변수를 통해 메모리에 값을 저장하기 위해서는 우선 필요한 저장 단위(byte)를 알아야한다. 이는 값의 종류에 따라 값을 저장하기 위해 확보해야할 메모리의 크기가 다르기 때문이다. 이때 값의 종류 즉, 데이터의 종류를 자료형이라고 한다. C-family언어는 정적타이핑 언어로 변수 선언 시 변수에 저장할 값의 종류에 따라 사전에 자료형을 지정하여야 한다.
변수를 선언하는 것부터가 메모리를 사용하는 것이기 때문에 변수사용을 최소한으로 하여, 페이지의 성능을 유지해야한다.
jacascript는 동적 타이핑 언어로(느슨한 타입: loosely typed) 변수의 Type annotation이 필요없이 값이 할당되는 과정에서 자동으로 자료형이 결정(Type Inference: 타입 추론)된다. 따라서 같은 변수에 여러 자료형의 값을 대입할 수 있다.
타입스크립트는 이런 동적 타이핑 언어의 단점을 보안하기 위해서 타입을 명시해주는 특징을 갖고 있다.
변수는 값을 저장(할당), 참조하기 위해 사용된다. 한번 쓰고 버리는 값이 아닌 유지할 필요가 있는 경우, 변수를 사용한다.
원시 값과 참조값 두가지 타입의 데이터를 저장할 수 있는데,
원시 값은 단순한 데이터이며
참조 값은 여러 값으로 구성되는 객체를 가리킨다.
변수에 값이 할당되면 자바스크립트 엔진
이 해당 값이 원시 데이터인지 참조인지 판단한다.
참조 값은 메모리에 저장된 객체이다. 다른 언어와 달리 자바스크립트는 메모리 위치에 직접 접근하는 것을 허용하지 않고, 객체의 메모리 공간을 직접 조작하는 일은 불가능하다.
참조로 접근한다
객체를 조작할 때는 객체 자체가 아니라 해당 객체에 대한 참조를 조작하는 것이다. 이런 이유로 객체를 가리키는 값은 ‘참조로 접근한다’고 한다.
참조 값을 다룰 때는 언제든 프로퍼티와 메서드를 추가하거나 바꾸고 삭제 할 수 있다.
원시 값에는 프로퍼티가 없지만 추가하려 해도 에러가 생기진 않는다.
동적으로 프로퍼티를 추가할 수 있는 값은 참조 값 뿐이다.
1 | let person = new Object() |
원시 값은 다른 변수로 복사할 때는 현재 저장된 값을 새로 생성한 다음 새로운 변수에 복사한다. 복사된 값과 원래 값은 완전히 분리되어 있다.
참조 값을 변수에서 다른 변수로 복사가되면 그 값이 객체 자체가 아니라 힙
에 저장된 객체를 가리키는 포인터
라는 점이다. 복사 후에는 두 변수는 정확히 같은 객체를 가리킨다. 따라서 한쪽을 조작하면 다른 쪽에도 반영된다.
스택메모리 공간은 함수호출 시마다 생성되고,
힙메모리 공간은 객체 생성 시 생성됨.
함수 매개변수는 모두 값
으로 전달된다. 함수 외부에 있는 값은 함수 내부의 매개변수에 복사된다. 변수는 값으로도, 참조로도 접근할 수 있지만 매개변수는 오직 값
으로만 전달된다. 메모리 공간을 확보하며 매개변수에 할당된다.
매개변수를 값 형태로 넘기면 해당 값은 지역 변수에 복사
된다. arguments 객체에 들어가게 된다.
typeof
1 | typeof 변수명 |
instanceof
1 | 변수명 instanceof Object |
https://github.com/rt2zz/redux-persist
redux-persist 정리할 때 purge에 대해서 구체적으로 작성해보겠습니다.
에러 메세지
1 | TypeError: In this environment the sources for assign MUST be an object. This error is a performance optimization and not spec compliant |
오류가 있는 persist 저장소를 갖고있어서 그럼.
https://github.com/rt2zz/redux-persist/issues/536
const persistor = persistStore(store);
를 찾아냅니다.persistor.purge();
를 넣고 다시 실행 (purge는 persistStore의 데이터를 전부 날리는 역할을 한다.)실습은 tic-tac-toc이라는 js 프로젝트를 마이그레이션 하면서 typescript를 연습해본다.
raect+typescript는 이웅재님의 강의 참고하였습니다.
역시 이론과 실습이 결합할 때가 제일 재밌다!
처음 프로젝트를 생성할 때 부터 타입스크립 버전으로 셋팅하는것이 제일 깔끔하다.
create-react-app ts-test --scripts-version=react-scripts-ts
create-react-app + 프로젝트 이름 + --scripts-version=react-scripts-ts
추가
PropTypes
컴포넌트 에서 원하는 props 의 Type 과 전달 된 props 의 Type 이 일치하지 않을 때 콘솔에서 오류 메시지가 나타나게 하고 싶을 땐, 컴포넌트 클래스의 propTypes 객체를 설정하면 됩니다. 또한, 이를 통하여 필수 props 를 지정할 수 있습니다. 즉, props 를 지정하지 않으면 콘솔에 오류 메시지가 나타납니다.
1 | // Content.js |
class에서 입출력되는 타입을 검토하기 위해서
배열의 요소가 객체일 경우
1 | interface GameState { |
return에 대한 출력값을 타입으로 명시할때
JSX.Element
return 내부가 JSX문법이므로 JSX.Element로 명시하였다.
1 | export default class Game extends React.Component<GameProps, GameState> { |
타입스크립트 정리 글은 이웅재님의 강의와 강의록을 참고하여 작성하였습니다. (짱짱)
오류가 있다면 언제든지 댓글 부탁드립니다.
코드를 읽기 좋게 하는 지름길
리터럴 타입
으로 추론1 | const array1 = []; |
1 | function hello(message: string | number) { |
리터럴타입의 ‘world’이거나 0이 나온다.
타입가드
Type guard어떤 Scope에서 타입을 보증하는 런타임 체크를 수행하는 몇 가지 표현식이다. 타입 가드를 정의하기 위해서, 리턴 타입이 Type predicate
인 함수를 정의 할 필요가 있다.
Type predicate
1 | parameterName is Type |
1 | interface Person { |
타입스크립트 정리 글은 이웅재님의 강의와 강의록을 참고하여 작성하였습니다. (짱짱)
오류가 있다면 언제든지 댓글 부탁드립니다.
요약
아직 잘 이해가 안간다. 😵
각자 Decorator의 시그니처가 다르다.
Decorator?
@
와 같이 써서 표현식 뒤에 오는 대상에 더욱 기능적으로 추가하거나 하는 일들을 할 수 있다.@
키워드를 이용해 선언된 함수를 Decorator로 사용할 수 있다. yarn add typeScript -D
여기서 D
는 dev
와 같은 명령어다.
여기서 helloFactory 는 팩토리 패턴
1 | function hello(constructorFn: Function) { |
1 | function addHello(constructorFn: Function) { |
1 | function editable(canBeEdit: boolean) { |
1 | function writable(canBeWrite: boolean) { |
1 | function printInfo(target: any, methodName: string, paramIndex: number) { |
타입스크립트 정리 글은 이웅재님의 강의와 강의록을 참고하여 작성하였습니다. (짱짱)
오류가 있다면 언제든지 댓글 부탁드립니다.
요약
아직 잘 이해가 안간다. 😵
es3for(var i = 0; i<array.length; i++)
es5array.forEach
: return으로 순회를 탈출할 수 없다.
es6for..of
for(const item of array)
원칙적으로는 배열에서만 사용이 가능하다.
for-of 루프는 이터러블 객체를 순회한다. for-of 루프는 이터레이터의 next() 메소드를 호출하고 next() 메소드가 반환하는 객체의 done 프로퍼티가 true가 될 때까지 루핑한다.
일반적일때는 사용하지 않는 것으로. (엔진에 따라 다르다.)
for (const prop of Object.keys(obj))
도 사용할 수 있다.1 | const array = ['first', 'second']; |
target 이 es3 인데도 forEach 는 트랜스파일이 되지 않았음.
https://github.com/Microsoft/TypeScript/issues/2410
1 | const array = ['first', 'second']; |
이터러블(iterable)
iterate = 반복하다
이터러블은 순회 가능한 자료 구조이다. Symbol.iterator
를 프로퍼티 key로 사용한 메소드를 구현하는 것에 의해 순회 가능한 자료 구조인 이터러블이 된다.
이터레이터
Symbol.iterator
를 프로퍼티 key로 사용한 메소드는 이터레이터로 반환한다. 이터레이터는 순회 가능한 자료 구조인 이터러블의 요소를 탐색하기 위한 포인터로서 next()
메소드를 갖는 객체이다. next() 메소드는 value, done 프로퍼티를 갖는 객체를 반환하며 이 메소드를 통해 이터러블 객체를 순회할 수 있다.
ES6에서 제공하는 built-in iterable은 아래와 같다.
Array.prototype[Symbol.iterator]
String.prototype[Symbol.iterator]
Map.prototype[Symbol.iterator]
Set.prototype[Symbol.iterator]
NodeList.prototype[Symbol.iterator]
HTMLCollection.prototype[Symbol.iterator]
1 | // lib.es6.d.ts |
객체는 이터러블이 아니다. 하지만 이터레이션 프로토콜을 준수하여 이터러블 객체를 만들수 있다.
1 | class CustomIterable implements Iterable<string> { |
타입스크립트 정리 글은 이웅재님의 강의와 강의록을 참고하여 작성하였습니다. (짱짱)
오류가 있다면 언제든지 댓글 부탁드립니다.
요약
제네릭은 어떠한 클래스 혹은 함수에서 사용할 타입을 그 함수나 클래스를 사용할 때 결정하는 프로그래밍 기법을 말한다. 정적 타입 언어에서도 이렇게 특정 타입을 위해 만들어진 함수 혹은 클래스를 보다 범용적으로 재사용하기 위한 요구가 있기 때문에 제네릭이라는 프로그래밍 기법이 생긴 게 아닐까한다.
any의 사용을 지양하고자 타입을 인자로 넘긴다.
하나의 타입만이 아닌 다양한 타입을 사용할 수 있도록 하는 기법이다.
한번의 선언으로 다양한 타입에 재사용이 가능하다는 장점이 있다.T
는 제네릭을 선언할 때 관용적으로 사용되는 식별자로 타입 파라미터(Type parameter)라 한다. T는 Type의 약자로 반드시 T를 사용하여야 하는 것은 아니다.1 | function helloGeneric<T>(message: T): T{ |
1 | function helloString(message: string): string { |
1 | function helloGeneric<T>(message: T): T { |
hello 함수의 제네릭 타입을 [] 를 이용하여 배열로 사용할 수 있음
1 | function hello<T>(messages: T[]): T { |
구현체에 return T 를 설정하지 않아도, return false 시 오류가 나지 않는다?
1 | type HelloGeneric = <T>(message: T) => T; |
명시적으로 제네릭 타입을 설정하면 오류
1 | class Person<T> { |
T 가 string 또는 number 를 상속받기 때문에 boolean 은 안된다.
1 | class Person<T extends string | number> { // union type |
1 | class Person<T, K> { |
keyof 키워드를 알아야한다.
1 | type Test = keyof Person; |
객체와 key값을 인자로 받아서 perperty의 타입값을 알아내는 함수를 만들었다고 치자.
함수에서 컴파일 타입을 검증할 수 있는 시스템이 필요하다. => type lookup system
getProperty
: Generic과 type alias를 결합하여 사용하여 type을 찾아낼 수 있는 시스템을 만든다.setProperty
: Generic과 type alias를 결합하여 사용하여 type을 찾아내고, 타입을 다시 재정의 하는 함수1 |
|
1 | interface Person { |
목차
(2017.10.01 ~ 2017.10.09)
각자 이름-페이지이름
으로 브랜치를 생성하기로 정하였다.규칙의 경우 예전에 참여했던 프로젝트의 규칙을 light하게 가져왔다.
규칙은 아래와 같이 가볍게 정했다!
Tip
close
, closes
, closed
, fix
, fixes
, fixed
, resolve
, resolves
, resolved
reopen
, reopens
, reopened
Issue
components/
global하게 사용되는 container 컴포넌트
pages/
container component와 presentational component를 함께 두었다.
Semantic-UI-React
서비스 컨셉과 유사한 디자인을 갖고 있고 여러 종류의 컴포넌트들이 있어서 사용.
!important
로 되어있는 css를 제외하고는 inline 형식으로 작성하기로 결정핫한 스타일드 컴포넌트를 쓸까 인라인 스타일로 작업을 할까 고민했었다. 지금 생각해보면 과감하게 쓸껄…이라고 생각이 든다. 러닝커브가 있을 듯 하여 인라인 스타일
로 작업하게 되었다.
Issue
인라인스타일로 작업하다보니 :hover
, :before
, :after
과 같은 셀렉터를 사용하지 못했고, css를 부분 부분 섞어 쓰게 되었다. 스타일드 컴포넌트는 이를 해결해주는데.. 그냥 쓸껄!
디자인 시안을 보면, 필요한 서드파티는
draft-js-export-html
로 해결react-vis
리액트 친화적.프론트엔드는 2명이었다. 각자 하고싶은 페이지를 맡아서 진행했다. 퍼블리싱은 항상 즐겁다! 🙆 퍼블리싱하면서 발생한 이슈만 정리하겠다.
react-router-dom
의존모듈
주 사용 API
App.js
에 셋팅
path
/
/diary
/diary/food
/diary/fitness
/diary/review
/report
/weight
/search/:sc
/recipe/:id
아래 자바스크립트를 타입스크립트로 바꾸시오
1 | function Car(name) { |
1차
1 | class Car { |
2차
1 | class Car { |
3차
1 | interface ICar { |
타입스크립트 정리 글은 이웅재님의 강의와 강의록을 참고하여 작성하였습니다. (짱짱)
오류가 있다면 언제든지 댓글 부탁드립니다.
요약
class에서 선언된 멤버변수와 멤버함수를 외부에서 접근이 가능하게 하는 방법, 재선언할 수 있도록 컨트롤하는 방법을 배웁니다. 생성자에도 private화하여 class 내부에서만 선언이 가능하도록 하며, 이는 singleTon 패턴을 정확하게 배치 가능할 수 있게 합니다. readonly 키워드를 붙여서 getter의 역할만 가능하도록 할 수 있습니다.
get, set을 하는 중에 무언가를 해주기 위해서 사용한다. get과 set 사이에 추가적인 작업이 있을 때 사용한다.
강사님은 getter setter가 혼란을 줄 수 있는 경우가 있어서 사용하지 않고, 대신 메서드를 같은 역할을 하는 메서드를 만드는데 메서드의 이름을 getName, setName으로 짓는다고 하셨따.
1 | class Person { |
getter
getter는 어떤 멤버 변수에 접근할 때마다 멤버 변수의 값을 조작하는 행위가 필요할 때 사용한다. 사용 방법은 아래와 같다.
setter
setter는 어떤 멤버 변수에 값을 할당할 때마다 멤버 변수의 값을 조작하는 행위가 필요할 때 사용한다. 사용 방법은 아래와 같다.
객체지향의 class와 거의 유사하다. static property와 static method가 있다.
1 | class Person { |
1 | class Person { |
public static은 의미가 있다.
private static 메소드와 프로퍼티는 무슨 의미가 있나?
대부분 한 ts파일에 한 class를 사용하고, 모듈을 다른곳에서 쓰기위해서 export import를 쓴다.
private static
?1 | class Person { |
1 | abstract class APerson { |
내부에서 생성하는 방법을 써야하고, 그러다보니 싱글톤 패턴을 정확하게 배치해서 사용할 수 있게 되었다.
1 | class Preference { |
자바스크립트의 함수는 new로 생성자를 사용할 때마다 새로이 생성된 객체를 리턴합니다. 하지만 특수한 상황에서는 하나의 함수에서 생성되는 객체가 오직 한개만을 가져야 할 때가 있다. 그럴 경우 사용되는 디자인 패턴이 Singleton Pattern
1 | class Preference { |
private인데 get, set중 get만 있는 상황과 같다.
private readonly
로 선언된 경우, 생성자에서는 할당이 가능하다.private readonly
로 선언된 경우, 생성자 이외에서는 할당이 불가능하다.public readonly
로 선언된 경우, 클래스 외부에서는 다른값을 할당할 수 없다.1 | class Person { |
타입스크립트 정리 글은 이웅재님의 강의와 강의록을 참고하여 작성하였습니다. (짱짱)
오류가 있다면 언제든지 댓글 부탁드립니다.
TL;DR
타입스크립트에서 주로 사용되는 class의 기초에 대해서 배웁니다. es6에 도입된 class
와, public, private, protected 키워드로 class에 접근제어하는 방법을 배우고, class간의 상속 개념을 배웁니다.
constructor
)가 없으면, 디폴트 생성자가 불린다.public
이 디폴트이다.1 | class Person { |
1 | class Person { |
private
private
으로 설정된 프로퍼티는 dot(.)
으로 접근할 수 없다.앞에 밑줄과 변수명을 쓰면 private이라는 코딩컨벤션 중 하나였다.
1 | class Person { |
protected
부모자식간의 관계에서 상속을 받은 class는(자식) 부모에는 접근 가능하다.
super란? super키워드는 부모 클래스의 프로퍼티를 참조할 때 또는 부모 클래스의 constructor를 호출할 때 사용한다.
1 | class Parent { |
1 | class Person { |
1 | class Person { |
extends
키워드를 이용한다.1 | class Parent { |
super
를 통해 부모의 생성자를 호출해줘야 한다.외부
에서 호출하는 것과 같다.protected
함수를 호출해서 그 안의 private 을 출력하는 것에 주의한다.1 | class Parent { |
Daily scrum +
Github +
개발부분부터 보길 원하신다면 다음 포스팅부터 읽으셔도 됩니다.
개발 공부를 하고 있던 만큼, 개발 이외의 시간들은 최대한 단축하고 싶었다. 우리 모두 비슷한 마음이었고, 다행히 이 부분의 스케줄을 잘 조정할 수 있었다. 사실 기획 스탭은 굉장히 중요한 시간이라는건 안다.. 한달이라는 기간이 주어졌기 때문에 선택과 집중을 해야하는 상황에서 우리는 개발기간을 선택했다. 다행히 각 스탭별로 능력을 갖고 있던 팀원들이 모였기 때문에, 이 부분에 대한 커뮤니케이션은 잘 진행되었고, 모두가 물어보는 그 3일만에 개발에 들어갈 수 있었다.
(여기서 말한 3일은 아이데이션 기간은 제외한 기간이다.)
목차
아이디어 논의 회의는 3일 중에.. 끝낸건 아니다ㅎ 그래도 2번의 회의 끝에 확정하게 되었다.
9월 7일 팀빌딩을 마치고, 25일 첫 팀프로젝트 오리엔테이션 전까지 2번의 회의를 진행했다.
서비스 주제의 경우, 요리
에 관심이 많던 팀원의 의견에서부터 시작했다. 요리로 키워드가 좁혀지고, 요리로 끊임없는 마인드맵을 그리다가, 첫 회의때는 주제는 결정하지 못했다.
그리고 첫 회의 때인만큼, 각자 하고 해보고싶은 테크에 대해서도 같이 얘기해보았는데, 그중 Google Cloud Platform (이하 GCP)의 Vision api
를 사용하자는 의견이 나왔다. 간단하게 얘기하자면 사진을 분석하여 어떤 물체가 있는 사진인지 단어를 여러가지 던져주는 api이다. 사실 이외에도 여러 의견들이 나왔었다. 일랙트론, 얼굴인식 api, 등등..
요리
로 좁혀졌다는 것.1차회의가 끝난 후 2차회의 전까지 집에서 이것저것 생각 해보았다.
다이어트 컨설팅
을 하는 언니가 떠올랐다. 그분이 주로 컨설팅 하는 방식은 컨설팅 받은 사람이 칼로리 계산과 영양소를 잘 조절해서 건강한 식사를 해 줄 수 있도록 도와주는 방식인데, 이때 사용하는 방법은 그 사람의 SNS에 무조건 식단 사진을 올리고 칼로리, 영상소를 기록하게 한다. 컨설턴트는 그 내용을 확인하고 1:1로 상담을 진행한다.오케이.
무조건 사진을 올려야한다는 조건과 음식이라는 조건이 일치했고, 2차 회의 때 제시해보았다. 저번 회의때 요리라는 키워드 때문에 레시피 서비스도 얘기했었는데, 레퍼런스를 찾다가 로푸드 레시피
를 제공하는 해외사이트를 공유한적이 있었다. 그때의 레퍼런스와 건강함을 추구하는 몇몇 팀원들 덕분에 ㅎㅎ 식단 다이어리 서비스로 확정.
바로 러프한 아키텍처를 구상하고 회의를 마무리했다.
팀 오리엔테이션때는 여러 재밌는 시간을 가졌는데, 프로젝트 시작 전 생각할 수 있는 위험요소를 공유하고, 어떻게 해결할지에 대해서 공유하는 시간을 가졌다. 지금 보니.. 귀여운 리스크들이네.
Risk
Solution
간단 오리엔테이션과 전체 진행 일정을 들은 후, 팀 회의 시간을 갖게 되었다. 이날은 저번에 짠 아키텍처를 시각화하고, 구체적으로 어떻게 컨셉을 잡을지와 UI구성, 서비스 네이밍, 등을 정했다. 이번 회의때는 몇몇 이슈들이 있었는데 저번 회의가 끝나고, 각자 머리 속으로 구성한 부분이 조금씩 달랐다는 점이었다. 이 날은 그런 생각의 차이를 조정하는 시간을 가졌다.
그리고 건강한 다
이어트를 위한 식단 다
이어리 서비스, DA DA 가 확정 되었다.
와이어프레임 ( PDF version + / Web version + )
프로토타입은 Invision, Sketch를 사용했다. 스토리보드를 참고하여 간단 목업스타일로 시안 작업을 진행했고, 인터렉션은 invision에서 작업, 전체 느낌과 컨셉을 확인하는 시간을 가졌다.
디자인은 간단하게 키워드를 잡고 진행했다. 심플 + 모던 + 산뜻
최대한 음식을 먹고싶은 욕구를 억제했으면 좋겠다는 생각이 들어서 붉은 계열의 색상은 피했다. 식욕억제를 목적으로 블루계열 색상으로 key color를 잡았고, 블랙과 키칼리가 비슷한 비율로 사용되었기 때문에 강약조절이 필요했고, 키칼라에 좀더 힘을 주려기 위해 그라데이션을 사용하였다.
프로토타입에서 목업작업을 잘 해놓았기 때문에 그래픽 작업에서는 수월하게 진행할 수 있었다. 역시 기초작업이 제일 중요.
최종 디자인 사안 이후 zeplin을 사용해서 팀원 전체와 공유하였다.
타입스크립트 정리 글은 이웅재님의 강의와 강의록을 참고하여 작성하였습니다. (짱짱)
오류가 있다면 언제든지 댓글 부탁드립니다.
TL;DR
inteface에 대해서 배웁니다. interface 내부에서 타입선언 후 변수에서 사용하며, 함수에서는 implements
키워드를 사용하여 interface를 상속받아 사용합니다. property를 ?
를 사용하여 옵셔널하게 사용가능하며(안써도 되는 프로퍼티를 명시할 수 있음) interface 끼리 상속이 가능합니다. interface 자체를 함수화하여 사용가능하며, 내부에서는 출력값과 입력값의 타입을 명시합니다. indexable type으로도 옵셔널한 프로퍼티를 만들 수 있습니다.
1 | const person: { name: string, age: number } = { |
1 | interface Person { |
1 | function hello(입력값:입력값타입): 출력타입 { |
1 | interface Person { |
1 | interface Person { |
1 | interface Person { |
1 | interface Person { |
indexable type으로 optional한 타입을 사용 가능하다.
1 | // 1. array같은 타입이고 |
person.anybody = "Clara"
.
을 붙인 후 프로퍼티로 타입을 옵셔널
하게 줄 수 있기 때문에 optional type으로 사용이 가능하다는 뜻이다. (없어도 에러가 나지 않는다.) string
이거나 number
만 가능하다.1 | interface StringArray { |
1 | interface StringDictionary { |
interface 내부에 함수를 넣을 수 있다.
1 | interface Person { |
interface를 상속받아서 class에서 사용가능하다.
implements
뒤에 인터페이스를 선언하면 해당 클래스는 지정된 인터페이스를 반드시 구현하여야 한다. 1 | interface IPerson { |
상속받는 인터페이스를 만들 수 있다. interface끼리 상속이 가능하다.
1 | interface Person { |
함수형 인터페이스이다.
사용할 때 한다
는 점을 명심1 | interface HelloPerson { |
타입스크립트 정리 글은 이웅재님의 강의와 강의록을 참고하여 작성하였습니다. (짱짱)
오류가 있다면 언제든지 댓글 부탁드립니다.
목표
이 포스팅과 interface 포스팅에서는 타입을 명시하는 방법을 배웁니다. 타입을 명시하지 않아도 추론이 가능하며, 강제 타입선언, 별명을 붙여가며 타입을 선언하는 방식 등을 배웁니다.
1 | let a: string = '진호'; |
리터럴 타입
이라고 하는 것으로 타입까지 강제해버린다.const d = '슬기'
에서 d는 const d:'슬기'
라고 뜨고, 슬기라는 리터럴 타입으로 된다.재할당 redeclare
보통은 const를 사용하며, let을 쓰면서 명시적으로도 값이 바껴지는 변수라고도 표시한다.
'타입이 이것이다'라고 컴파일러에게 알려주는 것
을 의미한다.넓은 범위의 타입
이 (union타입) 어떤 상황에서 고정이 되어야할 경우, 타입 어셜션으로 타입을 강제해 준다.1 | let someValue: any = "this is a string"; |
타입에 별명을 붙인다고 생각하면 된다.
type + 별칭
1 | // Aliaing Primitive |
1 | // Aliaing Union Type |
1 | // Aliaing Tuple |
보통은 interface와 class등을 자주 사용하기 때문에 alias 쓰는 타이밍이 초반에는 많이 없다. interface를 사용하다가 굳이 사용할 필요가 없는 순간에 alias를 쓰면 된다.
오류 메세지
타입스크립트가 컴파일을 시도할때 오류가 나올때, Alias라는 이름으로 알려주지 않고 타입 자체로 알려준다.
1 | type Alias = { num: number } |
상속을 받을 수는 있지만 상속을 할 수는 없다.
1 | type PersonAlias = { |
class A extends B
라고 하면class A implements C
라고 하면타입스크립트에서 기본 자료형을 잘!
숙지해야 한다. 타입스크립트는 타입을 새로 만들면서 짜는 방식인데, 특정한 골격을 갖출 때 결국 남는건 기본 자료형들이 남는다. 이때 기본 자료형이 정확히 어떤 것들이 있는지 인지하고 있어야, 그 기본 자료형들을 잘 조합해서 내가 사용할 인터페이스를 만들어 낼 수 있고, 타입을 만들 수 있다. 자바스크립트의 기본자료형을 모두 포함한다.
타입스크립트 정리 글은 이웅재님의 강의와 강의록을 참고하여 작성하였습니다. (짱짱)
오류가 있다면 언제든지 댓글 부탁드립니다 .
값 자체가 변하지 않는 값을 의미합니다 .
리터럴 상수
는 5, 1.23 과 같은 숫자나, ‘This is a string’ 혹은 “It’s a string!” 과 같은 문자열 등을 말합니다. 이것들이 리터럴 상수라고 불리우는 이유는 이것들이 프로그램 내에 직접 문자 형태
로 (literally) 지정되는 값들 이기 때문입니다. 이러한 값들은 한번 지정되면 변하지 않습니다 .
2
는 언제나 자기 자신이 2 라는 숫자임을 나타내며 어떤 다른 의미도 갖지 않습니다 .1 | let name = 'Nayoung' |
소문자 boolean 과 대문자 Boolean
Type 'boolean' is assignable to type 'Boolean'.
1 | let isDone: boolean = false |
1 | let decimal: number = 6 // 10진수 리터럴 |
string
형식을 사용한다.1 | let name: string = 'mark' |
1 | * 포함된 표현식은 `${ expr }`와 같은 형태로 사용합니다. |
1 | // 이 변수들에 할당할 수 있는 것들은 거의 없다. |
return
에서 주로 사용할당할 수 있다는 의미
입니다.--strictNullChecks
사용하면, null과 undefined 는 void 나 자기 자신들에게만 할당할 수 있습니다.1 | // 대입 가능 |
무언가가 있는데, 사용할 준비가 덜 된 상태.
(undefined 는 무언가가 아예 준비가 안된 상태
)object
입니다.1 | let n: null = null |
무언가가 아예 준비가 안된 상태
undefined
입니다.1 | let u: undefined = undefined |
1 | let list: number[] = [1, 2, 3] |
프리미티브 타입
의 값을 담아서 사용합니다.1 | let sym = Symbol() |
any
와 반대의 의미를 가집니다.리턴이 없을 때
사용합니다. 그 외에는 사용할 일이 거의 없습니다.
1 | function returnVoid(message): void { |
noImplicitAny
1 | function returnAny(message): any { |
1 | // Function returning never must have unreachable end point |
1 | // Declare a tuple type |
Da,Da 할때 아침 / 점심 / 저녁 / 간식을 Enum 타입으로 받았는데 , 이때 문자열
이였기 때문에*1
을 해줬었다 .
1 | enum Color {Red, Green, Blue} |
2016년 1월 1일은 금요일입니다. 2016년 A월 B일은 무슨 요일일까요? 두 수 A,B를 입력받아 A월 B일이 무슨 요일인지 출력하는 getDayName 함수를 완성하세요. 요일의 이름은 일요일부터 토요일까지 각각SUN,MON,TUE,WED,THU,FRI,SAT
를 출력해주면 됩니다. 예를 들어 A=5, B=24가 입력된다면 5월 24일은 화요일이므로 TUE를 반환하면 됩니다.
일별로 요일이 다르다.const day = ["FRI", "SAT", "SUN", "MON", "TUE", "WED", "THU"]
7일 day[0]
6일 day[6]
전체 일수가 x라면
x일을 7로 나눈후 나머지값 arr[x%7]
x의 값은 ?
0
31일 + b
31일 + 29일 + b
31일 + 29일 + 31일 + b
31일 + 29일 + 31일 + 30일 + b
31일 + 29일 + 31일 + 30일 + 31일
= 31일 * 3 + 30일 * 2 - 1
31일 * 3 + 30일 * 3 -1
31일 * 4 + 30일 * 3 -1
31일 * 5 + 30일 * 3 -1
31일 * 5 + 30일 * 4 -1
31일 * 6 + 30일 * 4 -1
31일 * 6 + 30일 * 5 -1
1 | function getDayName(a, b) { |
1 | function getDayName(a, b) { |
메소드 사용
1 | function getDayName(a, b) { |
템플릿 리터럴을 사용하지 않으면 값이 이상하게 나온다.
이유
1 | new Date(); |
** dateString*
날짜를 표현하는 문자열값
. 문자열은 parse 메소드에 의해 인식가능한 형식이어야 한다.
** year, month, date*
날짜의 각 부분을 표현하는 정수값
. 월(month)부분은 0부터 11까지의 값을 가지며, 0이 1월을, 11이 12월을 가리킨다.
때문에 템플릿 리터럴로 넣게 되면 문자열이 되어서 그대로 파싱하지만, 숫자일 경우 배열의 인덱스값으로 인지하여서 월의 시작숫자가 0이게 된다.
즉, let date = new Date(2016,a-1
,b) 이렇게 넣어야 한다.
타입스크립트 정리 글은 이웅재님의 강의와 강의록을 참고하여 작성하였습니다. (짱짱)
오류가 있다면 언제든지 댓글 부탁드립니다.
실제 프로젝트에서는 컴파일러 옵션을 그렇게 많이 셋팅하진 않는다 . 옵션을 셋팅할 수 있는 전체 스펙은 이 링크로 가면 확인가능하다 .
tsconfig.json 파일에서 제일 상위에 정의되어있는 컴파일 옵션들
파일 변경 후 저장하면 바로 컴파일을 해준다 . 에디터마다 안될 수도 있다.
보통 많이 사용하지 않는다 . 사용 예를 들면 , 클라이언트 타입스크립트와 서버사이드 타입스크립트가 있을 때, 설정이 비슷하다면 어떤 파일을 만든 후, 상속을 받아서 작은 부분만 바꿔서 쓰는 경우 사용 가능하다.
1 | // in config/base.json |
셋다 설정이 없으면 , 전부다 컴파일
files
include, exclude
glob 패턴 (마치 .gitignore)
include
exclude
항상 제외합니다 .
(include 에 있어도 )TypeScript 2.0 부터 사용 가능해진 내장 type definition 시스템
./node_modules/@types/
안의 모듈 이름에서 찾아옵니다 .typeRoots 와 types 를 같이 사용하지 않습니다 .
1 | // compiileOptions : type |
1 | { |
target
es3
입니다.lib
"noLib" : true
로 바꾸면 된다. ( 거의 안쓸듯 )1 | { |
module
commonjs
가 디폴트 입니다 .outFile 이 지정되어야 합니다 .
moduleResolution
paths 와 baseUrl
rootDirs
1 | { |
처음보는 옵션들이 있어서 정리해보았다 . 참고 : 타입스크립트 공식 페이지
allowSyntheticDefaultImports: true
import Something from './Something'
을 사용할 수 있다 .noImplicitAny: false
preserveConstEnums: true
allowJs : false
sourceMap : true
noImplicitReturns : true
noUnusedParameters : true
noUnusedLocals : true
프론트엔드 스쿨을 마지막 달에는 그동안 배운 기술을 토대로 프로젝트를 필수적으로 진행해야 했다. node.js 스쿨과 함께 5명으로 이루어진 우리 조는 33일간의 대장정을 끝으로, 알바퍼전의 웹서비스가 배포할 수 있게 되었다. 블로그에서는 프론트엔드 중심으로 이번 프로젝트에 대한 개인적인 후기와 더불어 전반적인 진행과정, 이슈에 대해서 5가지 챕터로 포스팅하려고 한다.
chapter 1 : 기획 및 프로토타입 및 디자인
chapter 2 : 퍼블리싱
chapter 3 : 핵심기능 개발
chapter 4 : 리팩토링 및 테스트
chapter 5 : 추가개발 및 배포
이번 프로젝트를 통해서 크게 3가지를 얻을 수 있었다.
프로젝트 이후 느낀점
우리 프로젝트에서는 다루는 데이터의 양이 많았었다. 매일 하루 3끼 식단, 운동, 일기, 등등. 이 데이터들을 rest API를 사용해서 rest하게 통신했지만, 해당 액션마다 필요한 데이터 + 필요 없는 데이터까지 가져오는 경우가 많았다. 이를 방지하기위해서는 백엔드에 엔드포인트를 요청해야했고, 여러면에서 낭비되는 리소스가 많이 발생함.
GraphQL과 Rest Api를 같이 써보자.
redux의 사용은 props로 액션을 주고받는 면에서는 혁신이다. 당연히. 그치만 많은 액션을 다루고, 관리하는 면에서 이건 액션으로 처리해야해. 라고 말하는 순간 귀찮음이 도지게 된다. 아 그럼 또 액션을 놓고 리듀서에 놓고 payload의 타입을 잘 지정해서 넣어주어야겠구나. 이런 불편함을 해소하고자 mobX를 사용하나 싶었다. 다음에 사용해보기
타입에 대한 이슈가 종종 있었다. 특히 이건 도대체 무슨에러인거지? 하면서 삽질할 때가 보통 타입때문에 생긴 에러들이었다. 객체형태로 들어오는지, 어떤 타입으로 타입을 내려주는지 등등을 console.log로 찍는건 한계가 있었고, PropsType으로 설정하는 것도 흠.
회사원인 수민이는 많은 일이 쌓여 있습니다. 수민이는 야근을 최소화하기 위해 남은 일의 작업량을 숫자로 메기고, 일에 대한 야근 지수를 줄이기로 결정했습니다. 야근 지수는 남은 일의 작업량을 제곱하여 더한 값을 의미합니다. 수민이는 1시간 동안 남은 일 중 하나를 골라 작업량 1만큼 처리할 수 있습니다. 수민이의 퇴근까지 남은 N 시간과 각 일에 대한 작업량이 있을 때, noOvertime 함수를 제작하여 수민이의 야근 지수를 최소화 한 결과를 출력해 주세요. 예를 들어, N=4 일 때, 남은 일의 작업량이 [4, 3, 3] 이라면 야근 지수를 최소화하기 위해 일을 한 결과는 [2, 2, 2]가 되고 야근 지수는 22 + 22 + 22 = 12가 되어 12를 반환해 줍니다.
]]>통과하고 싶다
현재 상황
팀 프로젝트인 식단 다이어리 서비스 dada 프로젝트에서는 db 설계에 대한 이슈가 없었다. 당연히 난 프론트엔드다보니.. db 설계를 담당하지 않아서인 건데, 현재 개인 프로젝트에서는 db 구조까지 짜는 작업을 하고 있다.
300개의 데이터와 개당 storage에 연동되어있는 파일들이 있는데, 제일 좋은 건 db에 url 칼럼을 넣는 방식. 파이어베이스에서는 스토리지와 데이터베이스 연결하는 것까지는 제공하지 않는 듯하다. 수동으로 작업해야 하는데 아직 좋은 방법이 떠오르지 않는다.
storage에 있는 데이터를 가져오는데, 현재 이슈.
]]>생각보다 db 짜는건 굉장한 노가다다! dada 프로젝트 할 때 백엔드 분께서 ‘생각보다 노가다도 많이 하게 되는데, 또 생각보다 어렵진 않더라구요!’ 라고 했던 말이 와닿는 하루다.
앞선 글에서 컴파일러와 트랜스파일러 인터프리터의 차이점을 알아보았다. 트랜스파일러와 컴파일러의 차이가 있다고는 했지만, 앞으로의 글에서는 컴파일러라고 통일해서 쓰려고 한다 . 타입스크립트는 컴파일드 언어라고 했지만 , 실제적으로 어떻게 환경을 셋팅하고 작업해야하는지 알아보자 .
타입스크립트 정리 글은 이웅재님의 강의와 강의록을 참고하여 작성하였습니다. (짱짱)
오류가 있다면 언제든지 댓글 부탁드립니다.
목표
타입스크립트를 사용하기 위해서 첫번째 실행환경을 셋팅하고 , 컴파일러 셋팅(npm으로 설치), 에디터에서 환경셋팅(tslint, 등등) 을 하고 , 간단하게 실습으로 컴파일 테스팅해본다. 기본 테스트가 완료되면 컴파일러 옵션을 어떻게 추가해야하는지 알아본다 .
런타임 환경
타입스크립트를 셋팅해 보자. 셋팅 방법에는 npm 과 VScode plugin으로 설치하는 방법이 있는데 , npm으로 설치해보았다 .
1 | npm i typeScript -g |
설치 후 node_modules 폴더의 bin파일에 tsc 파일이 생성되는 것을 볼 수 있다 ..bin
내부에 있는 파일들은 스크립트에서 경로 없이 파일 이름으로만 바로 실행시킬수 있다.
1 | node_modules/.bin/tsc 파일이름 |
타입스크립트로 만들어졌기 때문에 타입스크립트에 대한 지원이 강력 !
ts파일을 선택 후 하단 bar를 보면 Typescript라는 단어와 버전이 보인다. 버전을 누르면 옵션창이 보이게 되는데, 이는 VS Code에 내장되어있는 컴파일러 리스트 중 선택하라는 옵션창이다. 내장된 컴파일러 버전은 VS Code 가 업데이트 되면서 자동으로 올라가며, 컴파일러 버전과 VS Code 의 버전은 상관 관계가 있다. 내장된 컴파일러를 선택할수 있고, 직접 설치한 컴파일러를 선택할 수도 있다.eslint와 같이 코딩 컨벤션을 맞추기 위한 프로그램이다 .
1 | npm i typeScript tslint (로컬) |
tslint.json파일이 생성되고, 프로젝트에 맞게 코딩 컨벤션을 셋팅할 수 있다 .
https://palantir.github.io/tslint/
에디터에서 tslint 플러그인 설치
VScode : https://marketplace.visualstudio.com/items?itemName=eg2.tslint
tsconfig.json 파일에서 옵션을 추가하여 컴파일시 여러 조건을 걸 수 있다.
1 | tsc --init |
tsconfig.json 파일이 생성이 된다. 처음 생성시 디폴트로 되어있는 tsconfig.json파일
1 | { |
옵션에 대한 자세한 설명은 4번에서 설명!
1 | tsc -w |
셋팅 방법
1 | npm init -y |
tsc 파일이름.ts
명령어만으로 컴파일이 가능하다.cli 명령어로 명렁어를 다 걸어둘 수 있지만 json 파일을 만들어서 설정을 정리하며서 쓴다 .
최근 프로젝트를 진행하면서
나도 모르는 사이에 타입이 자주 바뀌는 자바스크립트의 불편함을 느끼곤 했었다. 애초에 값을 할당할 때 타입 체킹은 그 순간에 내 머릿속에서만 생각만 하지, 그 이후는 케어하지 못하게 되었다. 나중에 에러가 발생하면, 삽질
후에 원인이 타입 때문이라는 것을 알게 되고.. 이는 생각보다 빈번하게 일어났다. 콘솔에서 타입 에러를 잡지않고 렌더링이 될 때가 있기 때문에 타입으로 발생한 버그를 잡을 때는 시간이 더 걸린다.( 왜 에러가 나는 거여? 물론 리액트는 타입도 종종 잡아준다 . 무튼 시간 아까워! ) 버그 잡는 게 중요하긴 한데 , 타입이 원인이라는 것은 뭔가 어처구니없는 실수라는 생각도 들었다 .. 그러다 문득! 예전에 타입 버그가 날 때마다 타입스크립트를 배우면 이런 버그는 애초에 만나지 않을 겁니다!
라고 자주 얘기하셨던 선생님이 종종 생각났고 .. 게다가 지금 여러 프로젝트에서 타입스크립트을 도입하고도 있고, 얼마 후에 앵귤러도 시작하고자 해서 .. 겸사겸사 동기부여가 여러 군데에서 생겼기 때문에!! 시작!!
타입스크립트 정리 글은 이웅재님의 강의와 강의록을 참고하여 작성하였습니다 . (짱짱
) 오류가 있다면 언제든지 댓글 부탁드립니다 .
타입스크립트는 프로그래밍 언어 중 하나이다 . 자바스크립트가 인터프리터 기반의 언어로써, 실행과 동시에 렌더링이 되는데 , 타입스크립트는 인터프리터 방식이 아닌 컴파일 후에 실행되는 Compiled Language
이다 . 별도의 빌드 과정이 필요 ! 전통적인 컴파일 언어와는 다른데 , (C언어 , 자바 …) 때문에 Compile 말고, Transpile
이라는 용어를 사용하기도 한다 . 혹은 meta programming이라고 한다.
간단하게 3가지를 비교해보면 아래 그림과 같다.
transpiler 하나의 언어를 다른 형태의 언어로 변환해 주는 기능을 부각
시키는 표현으로 compiler라는 표현보다 transpiler라는 표현을 쓴다. ( 번역이라는 말과 합쳐진 듯 하다 .) ex. TypeScript, Babel
compiler 한 번 컴파일 하게 되면, 별도 생성된 목적 파일을 통해 빠르게 실행할 수 있다. 대용량 소스에 적합
interpreter 목적 파일 산출 과정이 없이 실행과 동시에 줄 단위로 번역이 된
다. 저용량 소스에 적합
Source Code
를 기계어로 변환하는 과정을 Compile
이라고Object Code
(목적 코드 )라 한다.Compile
하는 프로그램을 Compiler
라고 한다 .Compile
하는 동안을 Compile Time
이라고 한다 .정적 언어로 작성된 코드의 버그는 해당 코드를 실행하기 전까지는 찾을 수 없다.
intro
무언가를 배울때 하루하루의 기록을 남기는 것은 자기계발의 첫 스타트라고 생각합니다. 머리속에 있는 것을 그대로 옮기는 작업은, 정리하며 내것으로 만들기에도 좋고, 그때그때의 생각을 기록하는 용으로도 좋기 때문입니다. 그래서 우리는 일기를 쓰고, 일지를 쓰고, 이렇게 블로그도 만들며 기록합니다. 특히나 개발은 많은 개념을 숙지하면서 공부해야하기 때문에 블로깅 자체가 공부가 됩니다.
이왕 node.js
까지 배우고 있으니, jekyll
이 아닌, hexo
를 사용해서 블로그를 만들었습니다.
깃에 대해서 잘 알고 있다면 1번으로 넘어가도 됩니다.
### 0-1. 원격저장소[Git](https://backlogtool.com/git-tutorial/kr/intro/intro1_1.html)이란 소스코드를 효과적으로 관리하기 위해 개발된 '분산형 버전 관리 시스템'입니다.git은 저장소에서 관리를 하는데, 내 컴퓨터에 있는 저장소를 `로컬저장소`라고 하고, 웹 상에 있는 저장소를 `원격저장소`라고 합니다. 우리가 흔히 알고 있는 원격저장소를 제공하는 서비스에는 **깃헙, 비트버킷, 깃랩**등이 있습니다다. 헥소를 이용한 블로그 개설을 위해서는 **깃헙**을 사용해야합니다.### 0-2. 원격저장소 Github이 제공하는 정적웹사이트, Github PagesGithub에서 제공하는 Static Website, Github Pages가 있다. 깃헙 저장소에 리소스를 `push`만 해도(push란 저장소에 리소스를 넣을때 사용하는 명령어) 간단하게 웹사이트를 만들 수 있다. 즉, 다른 호스팅 서비스의 도움없이, 원격저장소에 올리기만해도 호스팅이 가능하다.### 0-3. 호스팅을 편리하게 만들어주는 generator, Jekyll & HEXO사실, hexo나 jekyll이 없이도, html,css,javascript를 통해서도 호스팅이 가능하나, 블로그 구성상 글을 등록하고, 리스트를 보여주며, 댓글을 달 수 있는, 블로그가 갖고 있는 기능을 편라히게 사용하기 위해서 hexo나 jekyll과 같은 generator를 사용해야 한다.
Static Website generator는 마크다운을(.md 파일)로 편집 후 html로 변환할 수 있도록 돕는다. generator에는 jekyll과 HEXO가 있는데, jekyll은 ruby
기반, HEXO는 node.js
기반이다.
그럼 generator을 셋팅하기 전, 내 컴퓨터에 디렉토리(폴더)를 생성하고, 원격저장소(github)에 연결을 시켜보자.
## 1. Github Pages로 정적 페이지 호스팅하기Github Pages를 사용하기 위해 Github의 원격저장소에 리소스를 올려야한다는 사실을 잊지말자. 아래 그림의 저장소들이 필요하다.### 1-1. 로컬에 저장소 생성하기내 컴퓨터 원하는 장소에 폴더를 생성한다.terminal없이도 생성해도 된다. 아래는 terminal을 이용한 생성방법1 | <!-- 바탕화면에 생성한다는 가정 |
바탕화면에 github-blog
라는 이름의 폴더가 생성이 되었다.
지금부터 말하는 USERNAME은, 당신의 아이디이다. 깃헙주소 뒷부분 /
이후 붙는 유저네임을 붙이면된다. 아래 순서로 깃 저장소를 생성한다.
USERNAME.github.io
로 적용한다. 위의 순서를 코드로 옮기면.
1 | <!-- 1. 해당 디렉토리로 이동 --> |
step 1이 끝났다! 그리고 벌써 호스팅이 완료되었다.
USERNAME.github.io에 가보자.
–
아직 블로그의 형태를 띄지 않았다. 위에서 말했던 generator를 이용하여 블로그의 구조를 짤 예정인데, 우리는 HEXO를 이용할 것이다.
Hexo는 말했다 싶이 node.js 기반이기 때문에 node.js가 로컬에 기본적으로 설치되어있어야 한다. node.js는 공식 사이트에서 설치가 가능하다. stable버전을 추천한다.
Node.js를 설치 한 후에 아래 CLI를 순서대로 입력하여 npm을 설치한다.
1 | npm install hexo-cli -g |
node.js를 설치하면 npm을 사용할 수 있는데, 패키지 중에 hexo-cli를 설치한다. blog파일을 생성하여 hexo를 초기화한다. blog 디렉토리로 이동후, npm install을 사용하여, blog에 필요한 파일들을 자동으로 설치한다.
위의 순서가 끝나면, root 디렉토리에 _config.yml
이라는 설정파일이 생성된다. (yml파일은 사람이 쉽게 읽을 수 있는 데이터 직력화 양식으로,…more) 해당 파일에 블로그 정보를 수정한다. 나머지 정보는 hexo 공식 문서에서.
Site 정보
블로그 정보를 수정할 수 있다.
1 | title: 제목(html head에 들어가는 title태그에 들어가는 제목과 같다.) |
URL 정보
블로그 URL 정보를 설정할 수 있다.
1 | url: https://USERNAME.github.io |
Github 정보
배포를 위해서 저장소 주소를 추가한다.
1 | # Deployment |
테마별로 구성을 수정하는 스타일이 다르다. 테마 적용하기 파트에서 anatol 레이아웃 수정방법을 설명하겠다.
### 2-4. 로컬에서 테스트하기1 | hexo server |
blog 디렉토리에 위치되어있는 상태에서 서버를 구동한다. blog에 위치되어있지 않으면 서버구동이 안된다. 서버 구동이 완료되면 4000번 포트로 접속이 가능하다.
테스트시 구동이 잘 안될 경우, 서버를 껐다가 다시 실행해 보면된다. 서버를 끄는 방법은 터미널에서 ctrl+c
를 두번 입력하면 된다.
1 | hexo generate |
위 명령어를 입력하면, github에 올라갈 리소스만 정리되어 따로 폴더가 생성된다.
1 | hexo deploy |
위 명령어를 입력하면 배고가 완료된다. generate와 deploy를 한번에 진행하고 싶은 경우 아래 명령어를 입력한다.
1 | hexo deploy --generate |
약자로 hexo d g
를 사용해도 됩니다.
1 | hexo clean |