코드스피치 강의 ES6+OOP 1회차 정리

September 06, 2020

Function & OOP

SUB ROUTINE FLOW

  1. FLOW

    • 메모리에 적재된 명령어가 순차적으로 ALU에 의해서 실행되는 과정
    • 한번 실행이 되면 중간에 멈출 수 없고, 명령어가 다 실행되기전까지 절대 멈출수 없다(Sync / 동기화명령)
  2. ROUTINE

    • Flow 그 자체를 의미한다
    • 메모리에 적재된 명령어를 한번만 실행하는게 아니라 여러번 실행시킬 수 있는것
  3. SUB ROUTINE

    • 현재 루틴안에서 일어나는게 아니라 밖에서 일어나면 다 서브 루틴(상대적인 관점)
    • 메인 플로우에서 서브루틴(하나의 또다른 루틴)를 호출시키면 flow가 이동하여 서브루틴안에 있는 명령어들을 다 실행하고 메인 플로우로 돌아오는게 특징
    • 서브루틴을 호출할때는 메인 플로우에서 다시 돌아올 지점을 같이 넣어서 호출한다(돌아올것)
  4. 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

  1. 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)
  1. 연산자로 인한 스택 메모리 생성

    • A만 실행시 문제가 없지만, A의 리턴값과 B의 리턴값을 가지고 연산을 하려고 하면 A 와 연산자를 저장
    • B가 실행되고 돌아올때까지 이전 결과값과 연산자를 메모리(스택)를 만들놔야지 연산 진행(아니면 성립불가)

Sub Routine in Sub Routine

  1. 서브루틴 안에 서브루틴

    • 서브루틴 상에서 또다른 서브루틴을 호출하려고 하면 지금 현재의 상태를 Snap Shot을 찍어서 가지고 있고 호출한 루틴이 끝나면 다시 돌아와 그 값을 이용하여 서브루틴을 끝낸다.
  2. 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

  1. Primitive Value

    • 메모리상에서 값이 복사되는 형태
    • 루틴으로 전달될때 값이 복사되서 넘어가기 때문에 의존성이 낮아진다(사이드 이펙트가 없다)
  2. 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

높은 응집도, 낮은 결합도

  1. 높은 응집도

    • 배열을 처리하기 위해서 다른 메소드를 부르는게 아니라 배열의 내장메소드를 이용한다
    • Math 내장객체는 높은 응징도(수학에 관련된 모든 함수)
    • 어떤 함수를 처리하기 위해 여러 함수를 호출하는게 아니라 하나의 함수만으로 처리한다
  2. 낮은 결합도

    • 어떤 함수를 사용하려면 앞에 40개의 함수를 가지고 있어야 해 높은 결합도
    • Math 함수 ⇒ floor round (필요할때 가져다가 쓴다 = 의존성이 제로)

COUPRING

  1. 정의

    • 의존성보다는 더 포괄적인 의미를 가지고 있다.
    • 의존성은 방향을 가지고 잇다. 커플링은 둘이 의존을 양쪽에서 하고 있다.
  2. 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))
  1. 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))
  1. 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);
	})
  1. 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')
  1. 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()
  1. 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

  1. COINCIDENTAL(우연히)

    • Util 같이 메소들이 아무런 관계가 없음. 다양한 이유로 수정됨
    const Util = class {
        static isConnect() {}
        static log() {}
        static isLogin() {}
    }
  2. LOGICAL

    • 사람이 인지할 수 있는 논리적 집합. 언제나 일부만 사용됨.
    • 동등한 지식을 가진 사람이 인식할 수 있는 수준의 응집된 함수의 모임
    • 도메인이 일반적이고 누구든지 알수있다면 진행(Math, URL)
    const Math = class {
        static sin(r) {}
        static cos(r) {}
        static random() {}
        static sqrt(v) {}
    }
  3. TEMPOLAL

    • 시점을 기준으로 관계없는 로직을 묶음.
    • 관계가 아니라 코드의 순서가 실행을 결정
    • 역할에 맞는 함수에게 위임해야 함.
    const App = class {
        init() {
            this.db.init()
            this.net.init()
            this.asset.init()
            this.ui.start()
        }
    }
  4. PROCEDURAL

    • 외부에 반복되는 흐름을 대체하는 경우
    • 순서정책변화에 대응불가
    const Account = class {
        login() {
            p = this.ptocken()
            s = this.stoken(p)
            if (!s) this.newLogin()
            else this.auth(s)
        }
    }
  5. COMMUNICATIONAL

    • 하나의 구조에 대해 다양한 작업이 모여있음.
    • 배열처럼 push/pop/slice 하나의 목적
    • 하나의 객체가 하나의 역할을 수행하는것이 좋다.
    const Array = class {
        push(v) {}
        pop() {}
        shift() {}
        unshift() {}
    }
  6. 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)
        }
    }
  7. FUNCTIONAL

    • 역할모델에 충실하게 단일한 기능이 의존성 없이 생성된 경우

결합도와 응집도는 서로가 다른 방향으로 향하게 되므로 둘 사이의 밸런스를 찾는 것이다.

추가

  1. 순수한 함수를 만들때 this가 필요해?

    • 함수는 에로우로 만들자
    • 메소드는 클래스 문법으로 만들자
  2. 자바스크립트는 리턴값을 정의하지 않으면 무조건 undefined가 된다

  3. undefined의 두가지

    • new Array(10) ⇒ 길이가 10인 undefiend
    • var a = undefined ⇒ 값이 undefiend
  4. es6부터는 객체의 키값이 선언한 순서대로 순서를 보장한다


© 2023, Customized by Joon