코드스피치 강의 ES6+OOP 1회차 정리
2020-09-06
Function & OOP
SUB ROUTINE FLOW
-
FLOW
- 메모리에 적재된 명령어가 순차적으로 ALU에 의해서 실행되는 과정
- 한번 실행이 되면 중간에 멈출 수 없고, 명령어가 다 실행되기전까지 절대 멈출수 없다(Sync / 동기화명령)
-
ROUTINE
- Flow 그 자체를 의미한다
- 메모리에 적재된 명령어를 한번만 실행하는게 아니라 여러번 실행시킬 수 있는것
-
SUB ROUTINE
- 현재 루틴안에서 일어나는게 아니라 밖에서 일어나면 다 서브 루틴(상대적인 관점)
- 메인 플로우에서 서브루틴(하나의 또다른 루틴)를 호출시키면 flow가 이동하여 서브루틴안에 있는 명령어들을 다 실행하고 메인 플로우로 돌아오는게 특징
- 서브루틴을 호출할때는 메인 플로우에서 다시 돌아올 지점을 같이 넣어서 호출한다(돌아올것)
-
MAIN FLOW vs SUB FLOW
- Main FLOW - Main routine이 실행되는 것
- Sub FLOW - Main flow에서 Sub Routine이 실행 되는것
// Main FLOW
const routineA = b => {
const result = b * 2;
console.log(result);
return result;
}
const routineB = d => {
const result = d * 3;
console.log(result);
return result;
}
const b = 10, d = 30;
const a = routomeA(b); // Sub Flow
console.log(a);
const c = routineB(d); // Sub Flow
console.log(c);
Communicate with routine
- MAIN FLOW와 SUB FLOW사이에서의 통신
- 위치 : MAIN FLOW에서 SUB Routine을 호출한 위치(되돌아올 장소)
- 값 : 인자(메인 ⇒ 루틴)와 리턴 (루틴 ⇒ 메인)
const routineA = arg => {
const result = arg * 2;
return result;
}
const b = 10, c = 20, d = 30;
const b = routineA(a) + routineA(b) + routineA(c);
-
연산자로 인한 스택 메모리 생성
- A만 실행시 문제가 없지만, A의 리턴값과 B의 리턴값을 가지고 연산을 하려고 하면 A 와 연산자를 저장
- B가 실행되고 돌아올때까지 이전 결과값과 연산자를 메모리(스택)를 만들놔야지 연산 진행(아니면 성립불가)
Sub Routine in Sub Routine
-
서브루틴 안에 서브루틴
- 서브루틴 상에서 또다른 서브루틴을 호출하려고 하면 지금 현재의 상태를 Snap Shot을 찍어서 가지고 있고 호출한 루틴이 끝나면 다시 돌아와 그 값을 이용하여 서브루틴을 끝낸다.
-
Keep
- 무리한 call stack은 stackover로 프로그램이 멈춘다.(크롬은 대략 100번 정도)
- 이러한 Keep을 call stack이라고 부른다 ⇒ Stack Memory에 저장
- Snap shot을 찍어서 저장하는 과정을 Keep이라고 부른다
const routineA = arg => routineB(arg * 2); // routineB를 호출하기전 routineB에 대한 상태값을 저장해놔야한다.
const routineB = arg => arg * 3;
const b = 10;
const a = routineA(b);
Value vs Reference
-
Primitive Value
- 메모리상에서 값이 복사되는 형태
- 루틴으로 전달될때 값이 복사되서 넘어가기 때문에 의존성이 낮아진다(사이드 이펙트가 없다)
-
Reference Value
- 공유된 객체의 포인터를 전달(전달된 객체를 바꾸면 원래값을 바꾼다??? 값은 원래값 하나뿐)
- 레퍼런스로 넘어온 경우, 포인터를 건드리지 않고 readonly로만 사용하고 만들어서 사용해라(사이드 이펙트)
const r = ({a,b, ...rest}) => rest;
const p = {a: 3, b : 4, c :5, d: 8};
const a = r(p)
p !== a
Structured Design
높은 응집도, 낮은 결합도
-
높은 응집도
- 배열을 처리하기 위해서 다른 메소드를 부르는게 아니라 배열의 내장메소드를 이용한다
- Math 내장객체는 높은 응징도(수학에 관련된 모든 함수)
- 어떤 함수를 처리하기 위해 여러 함수를 호출하는게 아니라 하나의 함수만으로 처리한다
-
낮은 결합도
- 어떤 함수를 사용하려면 앞에 40개의 함수를 가지고 있어야 해 높은 결합도
- Math 함수 ⇒ floor round (필요할때 가져다가 쓴다 = 의존성이 제로)
COUPRING
-
정의
- 의존성보다는 더 포괄적인 의미를 가지고 있다.
- 의존성은 방향을 가지고 잇다. 커플링은 둘이 의존을 양쪽에서 하고 있다.
-
CONTENT - 강결합
- A클래스 속성 v가 변경되면 즉시 B클래스 깨짐
- B클래스에서 A클래스의 속성을 다 볼수 있기 때문에
- 이렇게 대부분이 코딩을 하고 있으며, 하면 안된다.
const A = class {
constructor(v){
this.v = v;
}
}
const B = class {
constructor(a){
this.v = a.v;
}
}
const b = new B(new A(3));
-
COMMON - 강결합
- COMMON이란 전역객체, 공유객체, 인메모리에 안에 있는 객체를 의미한다.
- 1:1 구조를 COMMON으로 바꾼것일 뿐
const Common = class {
constructor(v){
this.v = v;
}
}
const A = class {
constructor(c){
this.v = c.v;
}
}
const B = class {
constructor(c){
this.v = c.v;
}
}
const a = new A(new Common(3));
const b = new B(new Common(3));
-
External 강결합
- 이 결합은 피할수 없다 정복해야 한다
- member.json에 의존적이라서 어쩔수 없다
- swagger 같은 것이 있어서 키랑 응답값에 대해서 정의
- 키가 없거나 다를 경우를 대비해서 throw 처리를 해줘야 한다.
const A = class{
constructor(member){
this.v = member.name;
}
};
const B = class{
constructor(member){
this.v = memver.age
}
fetch('/member')
.then(res => res.json())
.then(member => {
const a = new A(member);
const b = new B(member);
})
-
Control 강결합
- A 클래스 내부의 변화는 B클래스의 오작동을 유발
- flag를 기준으로 proces를 처리하기 때문에 문제가 많다.
- 팩토리 패턴에서 자주 발생되는 문제이며, 전략 패턴으로 해결해야한다.
const A = class {
process(flag, v){
switch(flag){
case 1:return this.run1(v);
case 2:return this.run2(v);
case 3:return this.run3(v);
}
}
}
const B = class{
constructor(a){
this.a = a;
}
noop(){
this.a.process(1);
}
echo(data){
this.a.process(2, data);
}
};
const b = new B(new A());
b.noop();
b.echo("test");
-
STAMP - 강결합 or 유사약결합
- A와 B는 ref로 통신함 ref에 의한 모든 문제가 발생할 수 있음
- A클래스는 단순히 add라는 행위에 초점을 둬야 하는데 객체로 받아오면 객체의 key가 변경이되면 오류 발생
- B클래스에서는 count 그 값자체만 주고 update는 본인이 해야함
const A = class{
add(data){
data.count++;
}
};
const B = class{
constuctor(counter){
this.counter = counter;
this.data = { a : 1, count : 0};
}
count(){
this.counter.add(this.data);
}
};
const b = new B(new A());
b.count();
b.count();
-
DATA - 약결합
- A와 B는 value로 통신함 모든 결합문제에서는 자유로워짐
- 하지만 A클래스에서 당연히 값이 온다고 가정했기 떄문에 데이터에 대한 커플링 발생
- 루틴간 통신하려고 할때는 값으로!!
const A = class{
add(count){
return count++;
}
};
const B = class{
constuctor(counter){
this.counter = counter;
this.data = { a : 1, count : 0};
}
count(){
this.data.counter = this.counter.add(this.data.count);
}
};
const b = new B(new A());
b.count();
b.count();
COHESION
-
COINCIDENTAL(우연히)
- Util 같이 메소들이 아무런 관계가 없음. 다양한 이유로 수정됨
const Util = class { static isConnect(){} static log(){} static isLogin(){} }
-
LOGICAL
- 사람이 인지할 수 있는 논리적 집합. 언제나 일부만 사용됨.
- 동등한 지식을 가진 사람이 인식할 수 있는 수준의 응집된 함수의 모임
- 도메인이 일반적이고 누구든지 알수있다면 진행(Math, URL)
const Math = class{ static sin(r){} static cos(r){} static random(){} static sqrt(v){} }
-
TEMPOLAL
- 시점을 기준으로 관계없는 로직을 묶음.
- 관계가 아니라 코드의 순서가 실행을 결정
- 역할에 맞는 함수에게 위임해야 함.
const App = class{ init(){ this.db.init(); this.net.init(); this.asset.init(); this.ui.start(); } }
-
PROCEDURAL
- 외부에 반복되는 흐름을 대체하는 경우
- 순서정책변화에 대응불가
const Account = class{ login(){ p = this.ptocken(); s = this.stoken(p); if(!s) this.newLogin(); else this.auth(s); } }
-
COMMUNICATIONAL
- 하나의 구조에 대해 다양한 작업이 모여있음.
- 배열처럼 push/pop/slice 하나의 목적
- 하나의 객체가 하나의 역할을 수행하는것이 좋다.
const Array = class{ push(v){} pop(){} shift(){} unshift(){} }
-
SEQUENTIAL
- 실행순서가 밀접하게 관계되며 같은 자료를 공유하거나 출력결과가 연계됨
- 프로시져와 커뮤니케이션의 복합체, chainning 함수
const Account = class{ ptocken(){ return this.pk || (this.pk = IO.cookie.get("ptocken")); } stoken(){ if(this.sk) return this.sk; if(this.pk){ const sk = Net.getSessionFromProken(this.pk); sk.then(v => this.sk); } } auth(){ if(this.isLogin) return; Net.auth(this.sk).then(v => this.isLogin) } }
-
FUNCTIONAL
- 역할모델에 충실하게 단일한 기능이 의존성 없이 생성된 경우
결합도와 응집도는 서로가 다른 방향으로 향하게 되므로 둘 사이의 밸런스를 찾는 것이다.
추가
-
순수한 함수를 만들때 this가 필요해?
- 함수는 에로우로 만들자
- 메소드는 클래스 문법으로 만들자
-
자바스크립트는 리턴값을 정의하지 않으면 무조건 undefined가 된다
-
undefined의 두가지
- new Array(10) ⇒ 길이가 10인 undefiend
- var a = undefined ⇒ 값이 undefiend
-
es6부터는 객체의 키값이 선언한 순서대로 순서를 보장한다