ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 객체지향 시스템과 패러다임 그리고 철학
    프로그래밍/설계 2021. 12. 14. 00:31

    자바스크립트는 왜 프로토타입을 선택했을까

    라는 글을 읽고 떠오르는 내용들을 덧붙이거나 정리 해보았습니다.

    원글과는 접근법이 좀 다르며, 기획이 아닌 급하게 쓴 글이라 의식의 흐름 사이에서 표류합니다 ㅠㅠㅠ

     

    빠른요약

    • 클래스와 프로토타입의 가장 커다란 차이는 객체 생성 방식 [클래스 -> 인스턴스 vs 객체 -> 복사된 객체].
    • 가장 큰 공통점은 객체지향이며, 프로그램을 객체라는 단위로 나누고 상호작용하게 하는 것.
    • 객체지향의 핵심인 캡슐화를 잘하기 위한 가장 간단한 방법은 추상화를 잘 하는 것.
      • 추상화는 데이터 위주의 성질(고전적 OOP), 형태(타입), 상태(데이터 주도 설계)와 관계 중심인 시간(절차지향), 행동(함수형), 정의(논리형), 상황(도메인 주도 설계, AOP) 등으로 나누어 생각할 수 있음.
      • 잘 분류하고 설계하기 위해서 사고의 형식을 인식하게 만드는 다양한 범주의 이해가 있다면 좋음 [예) 칸트의 4강 12목].
    • 철학과 패러다임
      • 절차형: 시간은 대부분의 추상화에 영향을 미치며, Goto처럼 컨텍스트가 섞이게 만드는 문법은 좋지 않음.
      • 함수형: 행동의 형태로 나타내려 하기 때문에 타입(형태)와 깊은 연관관계.
      • 논리형: 사실과 규칙으로 논리를 구성하고, 질의를 함으로서 술어논리의 결과를 얻을 수 있음.
      • 전통적 OOP: 직관적. 하지만 완벽한 속성을 알아내기는 불가능함.
      • 데이터 주도 설계: 로직의 상태를 다루려는 함수형과 달리 컴퓨터 자체에서의 상태를 줄이려 시도. 캐시 히트를 높혀서 성능향상을 가져옴.
      • 도메인 주도 설계: 전통적 OOP와 달리 도메인과 맥락에 따라 다르게 설계를 함(그림이론-용도의미론과 비슷), 서브도메인의 의존성 주입을 하는 AOP를 사용하면 구현이 편해짐.
    • MVP 
      • 프로토타입 제작: 중요한 기능이 포함되어야 하며 디자이너, 개발자, 재무등의 관점에 따라 달라질 수 있음. 많은 사람들이 중요하다고 생각하는 제품의 유사도에 따라 전형적인 요건.
      • MVP: 최소한의 완성도가 보장된 사용이 가능하고, 최종단계로 생각하는 제품과 유사하게 설계해야함.
    • 객체지향과 존재
      • 플라톤: 보편적 성질이 불변하며 실재하고, 개별적 존재들은 보편적 특성이 결여된 채로 존재한다 주장.
      • 아리스토텔레스: 개별적 개체만이 근본적 실체이며, 보편자는 상하/포함 관계에서 나타나는 표상이라 주장.
      • 클래스-인스턴스는 플라톤의 이데아론을, 프로토타입-복제된 객체는 아리스토텔레스 실체론과 유사. 

     


    0. 객체지향 들어서기

    객체지향의 주요구현 형태라 하면 Java, C++등에서 주로 사용하는 클래스와 Javascript, Io등에서 사용하는 프로토타입으로 나눌수 있다.

    커먼 리스프의 CLOS, 스칼라와 러스트의 Trait, 루비의 Mixin등도 있다고 하지만 가장 대표적이고 극적인 객체지향 형태는 저 둘이죠.

     

    클래스와 프로토타입 시스템의 가장 큰 차이는 무엇일까?

    새로운 객체로 분기하기 위해, 클래스는 new, 프로토타입은 clone으로 이루어진다는 것이다.

    Object object =  new Object();
    anObject := Object clone

    Java와 Io [작고 아름다운 언어 Io]

     

    둘은 대략 다음 표같이 생각해볼 수 있다.

    프로토타입 기반은 클래스와 인스턴스 구분이 없으므로, 당연히 static 메서드와 instance 메서드를 따로 나눌수 없다.

     

    반대로 공통점은 무엇일까?

    당연하겠지만 객체지향이라는 점이다.

     

    그럼 객체지향은?

    • 프로그램을 객체라는 단위로 나누고
    • 상호작용하게 하는 것이다.

    가장 간단한 정의라 할 수 있다.

     

    보통 객체지향을 설명하면 특징이 따라오며 특징이라 함은

    • 캡슐화: 변수와 함수를 단위로 묶음
    • 은닉화: 세부 구현이 외부로 드러나지 않게함
    • 상속성: 자식은 부모의 속성과 기능을 물려받음
    • 다형성: 상황에 따라 여러가지 형태를 가질 수 있음

    을 뜻한다.

     

    캡슐화는 어떻게 나누어야 할까를 고민한 결과이며, 상속은 이미 분류해 놓은 것을 재사용하기 위한 일종의 패턴이다.

    은닉화는 객체끼리 상호작용에 있어 노출을 줄여 의미있는 인터페이스만 노출하거나 보안을 유지할 수 있게한다.

    다형성은 상호작용이 이루어짐에 따라 특정한 기준을 만족할때 다른 동작을 하는 특성이다.

    많이 알려진 SOLID 원칙은 상호작용이 어떻게 일어나야 하는가에 대한 패턴이다.

     

    1. 추상화와 패러다임

    앞선 추론으로 객체지향에서 가장 핵심은 캡슐화임을 알 수 있으며, 묶기위해 어떻게 나눌(분류, classing)것인가에 대해 논의해볼 필요가 있다.

    분류하기 위해 간단히 생각해낼 수 있는 일반적인 방법중 하나는 추상화(Abstraction)이다.

     

    추상화 과정의 핵심은 특징을 뽑아내는 것이며, 유사도 또한 한가지 예라고 할 수 있다.

    지금 읽어보니 부끄부끄하지만 추상화 자체는 예전 썼놨던 글을 참고해보자. 

    https://black7375.tistory.com/6

     

    프로그래밍과 추상화에 대하여.

    HtDP를 읽는 중인데 오늘도 뻘 생각이 나서 그냥 필이 꽃힌 김에 적어봤다. (내 성격의 최대 장점이자 단점. 잡생각이 너무 많음. 글 중간에도 의식의 흐름대로 빠지는 것이 보인다.) 내 맘대로 하

    black7375.tistory.com

     

    1.1 분류

    보통 추상화는 다음과 같이 나눌 수 있을테며, 각종 패러다임은 추상화 방식이라 생각할 수 있다.

    모든 패러다임은 아니지만, 유명하거나 최근 떠오르는 패러다임은 기술하려 노력했습니다.

    (더 나은 정리나 정의가 떠오른다면 댓글 주세요!!)

     

    데이터 위주

    • 성질: 행동을 통해 나타나는 장기적인 특성
      • 예) 굵기, 색상
      • 패러다임) 우리가 보통 생각하는 OOP
    • 형태: 없다면 실체를 생각할 수 없는 것 (타입)
      • 예) 정수, 유리수, 문자열
      • 패러다임) 제네릭 프로그래밍과 타입 추론 시스템
    • 상태: 특정한 기준을 만족시키는 여러 구성 중 하나
      • 예) On/Off, 교착, 평형
      • 패러다임) 데이터 주도 설계(Data Oriented Design)

     

    관계 위주

    • 시간: 행위가 일어나는 시간
      • 예) 로딩, 렌더링
      • 패러다임) 구조적 프로그래밍(편의상 절차지향이라 표기하겠음)
    • 행동: 행동의 형태로 기술
      • 예) 사상(map), 필터, 리듀스
      • 패러다임) 함수형
    • 정의: 행동의 성질을 규정(사실 + 규칙, 제어)
      • 예) A와 B는 C관계가 있다,  A가 존재하는가?
      • 패러다임) 논리형
    • 상황: 정보와 활동 영역을 규정
      • 예) (대기업의) 배포, (스타트업의) 배포, (의료용 AI) 개발, (블로그 테마) 개발
      • 패러다임) 도메인 주도 개발

     

    분류를 위해 우리가 잘 설계해야 하는 것은 사고의 형식을 인식하게 만드는 다양한 "범주"라해도 과언이 아니다.

    철학에서 유명한 범주로는 칸트의 4강 12목과 헤겔의 범주론이 존재하며 칸트의 범주론은 아랫글의 초반에 나온 파트를 참고해볼 수 있다.

    아래 서술에서 사용되는 일부 단어가 이해되지 않는게 있어도 읽어볼 만하다. (정언판단 등)

    https://black7375.tistory.com/36

     

    내 맘대로 프로그램 설계 4. - 고정 크기 데이터.

    이번 섹션에서는 섹션2,3 정리와 고정 크기 데이터에 대하여 배우도록 하겠습니다. 다시 연재 시작했어요. 내 맘대로 하는 프로그램 설계 시리즈. Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [

    black7375.tistory.com

    칸트의 경우 한눈에 들어오게 정리해볼만 하나 헤겔의 범주론은 꽤나 복잡하다.

    헤겔은 내제된 모순성에서 준동되는 필연성을 이용해 절대정신을 설명하려 했던 사람이다.

    아무래도 모든 시스템을 하나로 설명하려다 보니 규모가 큰데다  특유의 논법으로 처음보는 사람은 이해가 쉽지 않을 것이다.

    https://ko.wikipedia.org/wiki/%EB%8C%80%EB%85%BC%EB%A6%AC%ED%95%99

     

    대논리학 - 위키백과, 우리 모두의 백과사전

    대논리학(『철학강요』-『Enzyklopädie der Philosophischen Wissenschaften Im Grundriss』-에 나오는 축약 형태의 논리학을 소논리학이라고 부르며, 이와 구별하여 단독 저작으로서의 논리학을 대논리학이라

    ko.wikipedia.org

    그는 변증법적으로 접근하기로 유명한데, 스텐포드 철학백과에 잘 나와있다.

    https://plato.stanford.edu/entries/hegel-dialectics/

     

    Hegel’s Dialectics (Stanford Encyclopedia of Philosophy)

    “Dialectics” is a term used to describe a method of philosophical argument that involves some sort of contradictory process between opposing sides. In what is perhaps the most classic version of “dialectics”, the ancient Greek philosopher, Plato (s

    plato.stanford.edu

     

    말이 나온김에 헤갤의 방식으로 수량(Quantity)은 어떻게 표시되나 한번 알아보자.

    • 정량(Quantum): "여럿"이 들어있는 밖 경계의 "하나"
    • 수(Number): 모든 측면에서의 "하나"
    • 크기(Extensive, 외연)와 세기(Intensive, 내연)양: 바깥 경계에 있는 "여럿"과 내부의 각각 "하나"
    • 도(Degree): 모든 측면에서의 "여럿"

    꽤나 합리적인 설명이지 않은가? 해설의 해설이 필요한 시점이다.

    특이해보이는 그림을 자세히 들여다보면 알 수 있을 것이다.

    • 정량: 정량한계란 단어를 바탕으로 이해하면 쉽다.
      정량한계는 바람직한 확실성을 가지고 정량할 수 있는 최저농도(수치상 유효한 의미)를 뜻한다.
      예를 들어 자는 1mm란 단위를 기준으로 "하나"라고 테두리에서 생각하지만, 1mm안에는 "여럿" µm, nm등이 모여있다.
    • 수: 내부의 "하나들", 겉의 "하나"들이든 모두 "하나"라는 것이다.
      예를 들어  1mm는 1µm 1000개로 구성되지만 둘 다 1이라 부르며, 책 하나나 비행기 하나나 모두 "하나"라 부른다.
    • 크기와 세기: 세기 성질과 크기 성질을 참고하면 쉽다.
      우선 세기는 변화가 가능하고 계의 크기와 무관한 성질이다. 계의 내부에서 각각 "하나"씩 존재한다.
      크기는 계의 크기에 비례하는 양이다. 따라서 각 세기들이 모여 만들어져 "여럿" 크기들을 규정한다.
    • 도: 은 두 반직선이 이루는 도형을 말하는데, 도는 각의 단위이다.
      안밖의 "여럿" 각도에서 본다고 생각해보자. 내각이든 외각이든 모두 "여럿" 도들로 이루어져 있다.

    2단원 각도('각'과 '각도'의 의미)

     

    이처럼 시스템의 안과 밖에서 "하나"와 "여럿"이 동시에 존재하는 것은 모순적이지만, 모순 덕분에 모든 시스템을 절대적으로 규정할 수 있었다.

    사각형 안과 밖/하나와 여럿의 모든 경우 $2^n = 2^2$개를 다루었기 때문이다.

    그럼 이 시스템에서 다룰수 없는 모순은 없을까?

     

    대표적인 것이 비례(Ratio)이다. 비례는 $1:2 = 3:6$처럼 수를 사용하지만 "하나"와 "여럿"만으로 정의하기 힘들다.

    이럴 때 필요한 것은 외부의 다른 개념!!

     

    비례는 양에 대한 보편 개념으로 자신의 내용 속에서 "여럿" 집합적인 성질을 가지고 있다.

    1:2와 3:6은 사상하므로 일대일 집합이라 할 수 있죠? 또한 2:4, 4:8.. 등등은 자신과 대등한 진부분 집합이라 할 수있어 무한집합 개념(둥근 사각형 전체)을 띄고 있다 말할 수 있습니다.

    집합과 무한에 대해 다룬적이 있으니 궁금하신분은 읽어보십셔.

    https://black7375.tistory.com/43

     

    무한, 집합, 그리고 수에 대해서.

    무한($\infty$)의 성질들을 집합과 수를 통해 간단하게라도 알아보도록 하자. M.C. Escher - Möbius Strip II(1963)[from Wallup] 1. 집합(Set)과 무한(Infinity). 무한의 성질을 알려면 집합에 대하여 아는 것이..

    black7375.tistory.com

     

    지금까지 나온 헤겔의 방식을 정리해보자면

    • 자기 자신(즉자적 존재)이 있다면, 모순이 내재하기 때문에 대자적인 존재는 필연이다. [하나와 여럿, 안과 밖, 수량과 비례 등]
    • 어떤 것과 다른 것 사이에서 왔다갔다하며 지양하게 되고 소거가 되는 동시에 보존된다.
      왔다갔다한 덕분에 포괄하게 되는 것이다. ("하나"와 "여럿"을 이용해 수량을 정의한 것을 생각하자)
    • 그렇지만 역시 또 모순이 존재하고 앞의 과정들을 반복하며 포괄적이고 보편적인 형태로 나아간다.

    라고 표현할 수 있다.

     

    한편 양과 항상 비교당하는 질(Quality)은 헤겔철학에서 대자 존재(자신과 대립하고 있는 것)의 보편적인 개념이다.

    이제 어느정도 감이 잡혔을것이라 생각한다.

    그렇다. 그의 세계는 모순에 의해 끊임없이 확장되는 세계다.

    여전히 쉽지는 않겠지만 헤겔의 범주론을 이해/이용하고 싶다면 위의 예를 상기해보기 바란다.

     

    1.2 설명

    진짜로 그러한지 알아보기 앞서 각종 패러다임을 소개하는 순서부터 정리해야 할 것 같다.

    전통적 객체지향 - 타입 - 데이터 주도 - 절차지향 - 함수형 - 논리형 - 관점 지향, 도메인 주도 설계 순서는 너무 뜬금없지 않은가?

     

    내가 생각한 순서는

    절차지향 - 함수형과 타입 - 논리형 - 전통적 객체지향 - 데이터 주도 - 도메인 주도와 AOP 순이다.

     

    말로 단번에 설명하기 어렵지만 한결 나아졌다는 느낌이다.

    어떻게 순서를 정했는가는 읽다보면 깨닫게 될 것이다.

     

    우선 이렇게 쪼개보았다.

    [절차지향] - [ 함수형과 타입, 논리형] - [전통적 객체지향 - 데이터 주도 - 도메인 주도와 AOP]

    집합끼리의 유사성이 느껴지는가?

     

    이번에는 주요기준을 적어봤다.

     시간         선언형                    객체지향 및 대체
    [절차지향] - [함수형과 타입, 논리형] - [전통적 객체지향 - 데이터 주도 - 도메인 주도와 AOP]

     

    절차지향, 시간

    시간이란 나누기 좋은 기준이다.

    다른 시간대에 존재하게 되면 확실성과 정합성이 깨질 확률이 높기 때문이다.

    보통 철학(논리학)에서는 올바른 사고를 위해 확실성(섞이지 않았는가), 정합성[충분한 근거를 가지고 있는가, 동일률, 비모순율, 배중률]을 꼽는다.

    예전 글 중간 쯤에 간단하게 정리해놓은적 있으니 역시 궁금하신 분들은 읽어보시기 바랍니다.

    https://black7375.tistory.com/34

     

    내 맘대로 프로그램 설계 3. - 함수와 변수.

    원래 합쳐져서 Section2 였던 '기초'에서 '간단한 데이터 처리'와 '함수'로 나뉘어 구성하게 되었습니다. 너무 길어서 로딩도 오래걸리고, 읽는 사람도 힘들겠더군요. 내 맘대로 하는 프로그램 설계

    black7375.tistory.com

     

    온갖 사이드 이펙트가 펼쳐지는 복잡계 시간의 흐름은 상호작용이 일어나는 것을 의미하고, 상태가 변하며 규약과 행동양식 또한 변한다.

    예를 들어 빅뱅, 공룡이 살던 시대, 산업혁명 전, 근대 모두 상태와 상황이 극심하게 바뀌었고 우리가 다루는 방식도 완전히 다르다.

    컴퓨터의 빠른 발전 및 등장한 시기를 고려할 때 가장 먼저 나타나 상당한 시간적 단절이 있으며,  다른 방법들에도 이미 적용되었다고 가정될만큼 기초적인 패러다임(공통된 성질), 이 글을 읽는 대부분이 알만한(공통된 상태)인 절차지향은 먼저 소개하기에 적절하다.

     

    절차지향이 나오기 전에는 Goto(jmp)문을 이용해 만들었다.

    Goto vs 절차지향[프로그래밍 모델]

     

     

    그러나 goto의 단점은 컨텍스트와 흐름이 섞여 나중에 알아보기가 매우 힘들다는 점이다. 

    시간이 뒤바뀐다면? [백투더퓨쳐1 (Back to the Future 1 : 1985)]

     

    물론 Goto가 무조건 나쁘다는 것은 아니다.

    중첩된 for문을 탈출하기에는 괜찮은 방법이며, FSM 구현이나 VM 구현때에도 유용하게(주로 성능 문제) 쓰이는 등 한정적인 용도로는 쓰이고 있다.

    Goto로 제어문을 만드는 방법이 궁금하면 어셈블리 게임 해보는 것도 ㅎㅎ

    https://store.steampowered.com/app/375820/Human_Resource_Machine/

     

    Human Resource Machine on Steam

    Program little office workers to solve puzzles. Be a good employee! The machines are coming... for your job. From the creators of World of Goo and Little Inferno.

    store.steampowered.com

     

    그러나 일반적인 용도로 사용하기에 적합하지 않다.

    앞서 말했듯이 컨텍스트가 섞이게 되면 의도치 않은 부작용이 크고 디버깅하기가 매우 힘들어지며 나머지 추상화를 거의 포기하는 것과 같다.

    일반적으로 for, while, switch와 같은 제어문, 함수들을 이용해 개발하며 Goto는 컨텍스트의 이동이라는 명확한 가치가 있을때만 사용하는 것을 추천.

     

    러스트에서는 중첩된 loop용으로 블록을 만들어 부작용을 최소화한다.

    https://doc.rust-lang.org/rust-by-example/flow_control/loop/nested.html

     

    Nesting and labels - Rust By Example

    It's possible to break or continue outer loops when dealing with nested loops. In these cases, the loops must be annotated with some 'label, and the label must be passed to the break/continue statement. #![allow(unreachable_code)] fn main() { 'outer: loop

    doc.rust-lang.org

     

    선언형

    최근 UI 부분에서 Flutter, Swift UI, Jetpack compose등 선언형 방식을 채택하는 경우가 늘어나고 있다.

    [Imperative vs. Declarative Kubernetes Management: A DigitalOcean Comic]

     

    선언형은 어떻게(How) 해야 하는지보다 무엇(What)을 강조한다.

    우리가 무엇을 해야할지 서술하면 구체적인 절차는 프로그램이 만들어주는 형태이다.

    장점이라하면 읽기 쉽고, 작성하기 쉽다는 것이다.

    단점으로는 돌아가는 모든 플로우를 제어하기 어려울 수 있어서 임베디드등 시스템 레벨에서는 맞지 않을 수 있겠죠.

     

    함수형과 타입

    [Programming Paradigm]

    앞서 함수형은 행동의 형태로 나타나기 위한 패러다임이라 하였다.

    그런데 형태를 기준으로 사고하는 방식이 있었다.

    바로 타입(자료형).

     

    [What is Purity?, Exploring Clojure (and FP vs OOP)]

    만약 함수가 행하려는 형태(input/output)를 표현하기 어렵다면 함수형 프로그래밍을 하기 어려워진다.

    정적 타입인 함수형 언어들에서 정교하게 타입 시스템을 구축하려 노력하는 이유일 것이다.

     

    반대로 생각하면

    자료형들에 따라 할 수 있는 행동이 달라지거나 제약된다.

    예를 들어 숫자와 문자는 1 + 1 = 2, "가" + "나" = "가나"처럼 달라질 수 있고, "가" / "나"할 수 없듯이 자료형에 따라 제약되는 경우가 생긴다.

     

    일반적으로 생각할때 하나로 묶을수 있는 자료형들이라 할지라도, "없다면 실체를 생각할 수 없는 것"이기 때문에 비슷한 행동을 하지만 다른 자료형들로 분리되어 존재한다.

    같은 숫자지만 컴퓨터라는 한계(일반적인 정수/실수와 다르게 크기와 정확도등의 제한됨)에 의해 int, double등과 같이 형태를 정의해야만 실체가 생길 수 있는 것이다.

    일정한 제한 내에서 같은 연산자나 함수를 가지더라도 다른 형태이므로 또 서술해야 하는 상황을 막기 위해 제네릭(Generic)으로 추상하여 표현하기도 한다.

     

    다시 함수형으로 돌아와서, 함수형은 행동을 형태로 기술해야 하는데 중간에 만약 형태가 바뀐다면??(상태가 있음)

    함수형을 지향함에 있어 문제가 생기는 것이다.

    따라서 Stateless와 순수함수를 지향하며, 불변자료구조를 사용하고 모나드와 같은 것을 사용해 어쩔수 없는 상태(I/O 같은것)를 감싸 해결을 하려 시도한다.

     

    느긋한 평가(Lazy eval)의 경우 순수함수라서 생길 수 있는 특징이며 커링(Curring, 인자를 하나씩만 받음)등을 이용한다.

    모든 인자값을 더해야 하는 함수를 커링화했다고 생각하면 이러합니다.

    add(2)(3)(5)(6) // ...

    계산을 미루므로 리소스를 절약이 가능하며, 무한을 다루기에도 효과적이다.

     

    함수형과 관련된 글들은 많이 써두었으니 이 이상은 여기에서는 설명하지 않겠다.

    https://black7375.tistory.com/62

     

    내 맘대로 프로그램 설계 7. - 함수형 프로그래밍.

    내 맘대로 하는 프로그램 설계 시리즈. Chapter1 - 간단한 데이터 처리(4섹션) 2017/12/27 - [프로그래밍/설계] - 내 맘대로 프로그램 설계 1. - 이유와 준비. 2018/01/11 - [프로그래밍/설계] - 내 맘대로 프로

    black7375.tistory.com

    https://black7375.tistory.com/69

     

    간단한 모나드 설명과 예제

    리엑트 네이티브 스터디 때문에 시작한 글이었는데 생각보다 길어져서 분리하게 되었다. 자바스크립트 관련 코드는 해당 스터디쪽 문서에 올릴 예정. 역시 모나드를 이해할때는 Haskell이 가장

    black7375.tistory.com

    https://black7375.tistory.com/71

     

    자바스크립트와 함수형 프로그래밍.

    React Native에서 사용하는 React는 함수형 프로그래밍의 철학을 받아들여 만들어졌습니다. React를 처음 접하는 이들을 위한 문서에서도 함수형 프로그래밍의 특징중 하나라는 불변성을 강조하고 있

    black7375.tistory.com

    불변 자료구조 예시

    https://timbaumann.info/pfds-visualizations/

     

    Purely Functional Queues

     

    timbaumann.info

     

    함수형과 철학에 재밌는 점을 꼽아보자면 함수형에서 형태로 나타나기 위해 자주 사용되는 기법 중에 하나인 재귀가 변증법적이라는 것이다.

     

    설명이 너무 길어질까봐 못하겠지만, 재귀함수와 비슷하지 않은가?

    비록 설명은 아니지만 관련성에 대해 간단히 서술한적은 있었다.

    관심 있는 사람은 앞서 나온 설명과 비교하며 읽어보자.

    https://black7375.tumblr.com/post/175291125910

     

    재귀가 아름다운 이유.

    재귀가 아름다운 이유. 결론적으로 말하자면 내재적 정합성과 필연성을 가지기 때문이다. 재귀가 왜 아름다운지를 알기하기 위해서 우선 재귀의 과정을 파악할 필요가 있다. 재귀의 과정. 잘 만

    black7375.tumblr.com

     

    논리형

    논리형이 재미있는 까닭은 로직과 컨트롤을 분리시켜 놨다는 것이다.

    논리형에서 말하는 논리(Fact + Rules)는 철학에서 말하는 논리와 거의 동일하다.

    [Prolog - Introduction]

     

    이성론자들이 말하는 사고는 선험적(내재적)이며, 언표(apophansis)로서 표현한다.

    간단히 언표는 "말로 나타낸 바"라 할 수 있으며,  문장에서 핵심이 되는 주어와 설명하는 술어로 이루어진다.

    주어와 술어가 말이 되게 만들어주는게 바로 논리라 할 수 있다.

     

    술어논리를 기술할 수 있게 만들어진 프롤로그의 코드를 보여주며 말하자면 [인공지능언어 PROLOG, Prolog 논리 프로그래밍 언어]

     

     Fact는 일종의 정언판단이다. (실체와 속성을 의미하며, 정언명령과는 다름)

    일반적인 주어-술어 관계라 생각하면 이해가 쉽다.

    • 존은 사람이다.
    • 메리는 사람이다.
    • 존은 와인을 좋아한다.
    • 메리는 와인을 좋아한다.
    % Facts
    human(john).
    human(mary).
    likes(john, wine).
    likes(mary, wine).

    를 기술했다.

     

    Rule은 가언판단(원인과 결과)등을 기술할 수 있다.

    • 사람은 죽는다.
    • 존은 와인을 좋아하는 사람을 좋아한다.
    % Rules
    likes(john, X):-likes(X,wine).
    die(X):-human(X).

     

    룰을 기술함으로서 삼단논법과 같은 추론이 가능해진다.

    • 존은 죽는가? - 참
    • 존은 메리를 좋아하는가? - 참
    • 누가(X)가 죽는가? - 존, 메리
    % Query
    ?-die(john).
    ?-likes(john, mary).
    ?-die(X).

     

    고전논리에서는 술어논리라는 개념이 없었기 때문에 추론이 불가능했지만, 수리논리를 주로 연구하던 프레게 덕분에 가능해졌다고 알려져있다.

    이러한 면에서 논리형은 상당히 철학과 밀접한 패러다임이라 볼 수 있다.

     

    객체지향 및 대체

    바로 설명에 들어가볼까요?

     

    전통적 객체지향

    객체지향은 프로그램 패러다임을 나눌때 항상 같이 등장하는 공통된 성질을 가지고 있다.

    사이드 이펙트가 적고 단순한 형태라는 가정하에 성질을 기반으로 나뉘어 있다면 구분하기 쉬우며 직관적이다.

    직관에서 오는 생산성은 전통적인 OOP가 오랫동안 지배해왔던 이유이기도 하다.

     

    OOPs Vs Procedural Programming

     

    심지어 GTK와 리눅스 커널은 OOP를 지원하지 않는 C언어를 쓰면서도 OOP적인 방법을 지원한다.

     

    성질이 존재하는지, 또 어떻게 인식되는지는 철학에서 다룰수 있는 주제다.

    이는 추후 클래스와 프로토타입을 철학과 연결할 때 다시 언급하도록 하자.

    여기에서는 어떠한 존재의 완벽한 속성을 알아내고 인식하는 것은 불가능하다고만 알아두면 된다.

     

    데이터주도 설계

    난 데이터 주도 설계를 상태변화를 최소화하기 위한 설계라고 생각한다.

     

    상태와 시간에 대해서 조금 더 생각해보자.

    시간의 변화를 물리학에서는 다음과 같이 정의하고 있다.

    시간 변화(時間變化, time evolution)는 시간의 흐름에 따라 계의 상태가 바뀌는 과정이다.

    위 내용을 설명하려면 긴 내용이 필요하므로 생략하고 우리에게 필요한 의미를 뽑아보자.

     

    • Stateless하면 시간이 흐르지 않았다는 말이다.
    • 상태변화가 적으면 시간이 적게 흘렀을 가능성이 높다. [시간적 지역성, 미래에서 참조하기 쉬움]
    • 상태변화가 적은 것끼리 모아두면 참조하기 편하다. [공간적 지역성]
    • 상태변화를 순차적으로 일어나게 하면 자연스럽다. [순차적 지역성]

    상태를 기준으로 추상화를 하면 성능이 올라갈 수 있다는 말이다.

    이는 컴퓨터뿐만 아니라 인간의 뇌 또한 좋아하고 직관적이라 느낀다.

     

    여러가지 주제가 섞인 이 파트, 글의 순서 또한 이를 고려한 방식으로 설계되어 있다는 것을 알 수 있을 것이다.

    클래스/프로토타입[차이, 유사성] - 추상화와 패러다임[분류, 설명(절차지향..객체지향)] - 객체지향과 존재

     

    OOP vs  DOD  [twitter] - DOD는 상태가 줄어들고 비슷한 값끼리 묶여 지역성이 늘어난다.

     

    어??  아까 상태 변화를 제거하기 위해 노력하던 패러다임이 있었죠?

    바로 함수형.

     

    그러나 함수형 자체로는 대규모가 아니면 성능에 한계가 있다고 알려져 있다.

    현재로선 함수형이 시도하는 방법은 로직자체의 상태변화를 낮추려는데 의미가 크다.

    리스프 머신이나 The Reduceron(HN)같이 함수형에 특화된 아키텍처가 보급된 상황이 아니기 때문이다.

    컴퓨터 자체(튜링머신)의 상태와는 다른 기준이라는 것.

     

    반면 데이터 주도 설계는 현재 컴퓨터 설계를 기준으로 상태 변화를 낮추려고 시도한다. [Introduction to Data-Oriented Programming, Data Oriented Design Resources]

     

    아주 간단한 예를 들고 와봤다. [An introduction to Data Oriented Design with Rust]

    구조체를 사용하는 예제이지만 클래스나 기타 OOP 구현에서도 충분히 사용할 수 있는 기법이다.

     

    걸리는 시간 차이

     

    구조체 각 속성을 넣어두고 계산하는 방식보다

    pub struct Player {
        name: String,
        health: f64,
        location: (f64, f64),
        velocity: (f64, f64),
        acceleration: (f64, f64),
    }
    
    pub fn run_oop(players: &mut Vec<Player>) {
        for player in players.iter_mut() {
            player.location = (
                player.location.0 + player.velocity.0,
                player.location.1 + player.velocity.1,
            );
            player.velocity = (
                player.velocity.0 + player.acceleration.0,
                player.velocity.1 + player.acceleration.1,
            );
        }
    }

     

    배열이나 백터와 같이 연속적인 자료구조를 만들어놓고 관리하는 방식이 성능이 훨씬 낫다.

    pub struct DOPlayers {
        names: Vec<String>,
        health: Vec<f64>,
        locations: Vec<(f64, f64)>,
        velocities: Vec<(f64, f64)>,
        acceleration: Vec<(f64, f64)>,
    }
    
    pub fn run_dop(world: &mut DOPlayers) {
        for (pos, (vel, acc)) in world
            .locations
            .iter_mut()
            .zip(world.velocities.iter_mut().zip(world.acceleration.iter()))
        {
            *pos = (pos.0 + vel.0, pos.1 + vel.1);
            *vel = (vel.0 + acc.0, vel.1 + acc.1);
        }
    }

     

    개발자에게 직관적인 방식으로 이해할 수 있는 그림을 들고오자면

    Data-Oriented vs Object-Oriented Design

    위와 같다.

    캐싱과 자동 벡터화, 분기예측등 각종 최적화 혜택을 받기에 좋아보인다.

     

    그리고 DOD를 적극적으로 활용하기 위해 나온 패턴이 있는데 ECS(Entity Component System)이라 한다.

    전통직인 OOP와는 다소차이가 있지만 유니티에서 DOTS라는 이름으로 도입했으니 관심있는 분은 확인해보길 바란다.

     

    도메인 주도와 AOP

    도메인 주도와 AOP에 대해 이야기 앞서 비트겐슈타인의 그림이론과 용도의미론에 대해 설명할 필요가 있다.

    그림이론은 그의 전기이론[논리-철학 논고], 용도의미론은 후기이론[철학적 탐구]의 대표적인 개념이다.

    비교적 쉽게 설명해 놓은 글이 있다. [비트겐슈타인(2)-전기 사상 : 언어그림이론-모사설, 비트겐슈타인(8)-후기 사상 : 용도의미론(the use theory of meaning)]

     

    우선 이름이나 각종 개념들은 어떻게 생겨나는 것일까?

    호랑이, 사자와 같은 대상, 사냥하다나 잠자다와 같은 술어등 모두 "공통된 요소들을 추상하여 합친 관념"이거나,  "공통된 요소들을 참조하여 나타난 표현"이라 할 수 있다.

     

    각종 개념들은

    • 호랑이, 사자와 같이 경험적일수도
    • 유니콘과 해태처럼 상상일 수도
    • 철학, 객체지향처럼 파생적일 수도 [임의적인 이름과 정의]

    있다.

     

    전기 비트겐슈타인은 기존 철학의 문제가 말할 수 없는 것을 말하려 하기에 문제가 일어난다고 생각했다.

    플라톤의 이데아를 떠올려보자.

     

    이데아를 가장 잘 설명하는 것은 동굴의 우화이다.

    동굴의 우화

    구속되어 있는 사람(우측)의 사람은 그림자만 볼 수 있고, 그림자가 "실체"라 생각한다.

    우리가 현실에서 볼 수 있는 것 또한 이데아(실체, 참된 세계)의 그림자 뿐이다.

     

    왜냐하면 우리가 인식할 수 있는 것은 한계가 있기 때문이다.

    인간의 오감만으로 세계의 모든것을 관측할 수 있는가?

    절대적으로 그렇지 않다.

     

    모사설은 이러한 주장에서 나온다.

    우리의 지식/인식은 이데아를 모방하는 것 뿐이며, 진리는 이데아와 일치할때 발생하는 것이라는 것이다.

     

    "언어는 세계의 그림이다"라는 그림이론도 비슷하다.

    언어로 세계를 표현하며(그리며), 표현이 맞다면 진리이며, 아니라면 올바른 지식이 아니라는 것이다.

    따라서 말할 수 없는 것(표현할 수 없는 것)에 대해서 침묵해야 한다고 생각했다.

    올바르지 않기 때문이다.

     

    그림이론에서

    • 언어는 세계를
    • 명제는 사실을 [요소명제-원자사실, 복합명제-복합사실]
    • 이름은 대상을

    지칭한다.

     

    앞서 우리는 프롤로그라는 언어로 세계를 표현한 적이 있다.

    % Facts
    human(john).
    human(mary).
    likes(john, wine).
    likes(mary, wine).
    • "존은 사람이다"라는 복합사실은
    • "존"과 "사람"이라는 원자사실의 결합이다. (더 이상 나뉠수 없고 독립적임)
    • "존"과 "사람"은 존과 사람 각각의 공통된 요소들을 추상한 "대상"을 지칭하는 "이름"이었다.

     

    그러나 위의 세계(그림이론)에는 치명적인 문제들이 존재한다.

    우선 존이 사람이라는 요소명제는 증명이 불가능하기 때문이다.

    만약 캐스트어웨이의 윌리같은 존재라면..? [톰행크스의 무인도표류기 캐스트어웨이]

     

    반드시 사람이라는 것이 맞다는 필연판단[진리]이 아니라 존이 사람이든 아니든 일단 사람으로 가정하는 실연판단이라는 양상이라는거죠.

    사람이 아니더라도 세계의 "판단 자체"에는 영향을 끼치지 않습니다.

    판단이 맞다면 가치가 있는 것이고, 아니라면 가치가 없을 뿐이다.

     

    만약 올바른 판단을 할 수 없다면?

    전기 비트겐슈타인에 따르면 침묵하는 것이 맞습니다.

    이렇게 되면 많은 것을 침묵해야 한다는 결과가 도출됩니다.

     

    두번째. 일대일 대응이 가능한 가이다.

    이 글을 쓰게된 자바스크립트는 왜 프로토타입을 선택했을까에서도 "벽돌!!"로 설명했습니다.

    상황마다 언어의 의미는 달라졌음을 다시한번 떠올려보자.

    • 초보 제자에게: 벽돌!!
    • 성숙해진 제자에게: 벽돌!!
    • 벽돌이 떨어지는 곳에 있는 제자에게: 벽돌!!

     

    제자는 각 상황에 따라 게임을 하듯이 정답을 맞추어야 했다.

    • 벽돌을 달라.
    • 벽돌을 채우라
    • 벽돌을 피하라

    그래서 후기 비트겐슈타인은 이를 언어놀이라 불렀다.

     

    또 다른 예시들[맥락적 사고의 중요성]

     

    그렇다. 텍스트가 같다 하더라도 상황과 맥락에 따라 다르게 해석된다는 것이다.

    절차지향 파트의 링크에 제가 요약해놨던 동일률의 설명과 상동한다. (관점에 따라 동일하게 보는게 다름)

     

    전통적인 OOP와 도메인 주도 설계는 그림이론-용도의미론의 관계와 유사하다.

    전통적인 OOP에서는 속성관계를 완벽하게 정의하려 했지만, 도메인 주도 설계는 컨텍스트에 따라 정의한다.

    도메인 주도 설계에 대한 글은 SK C&C에서 체계적으로 소개하고 있습니다.

    도메인 전략 설계를 적용하는 모습을 보려면 다음 블로그도 괜찮습니다. (지식을 가지고 있다고 가정)

     

    우선 도메인은 실세계에서 사건이 발생하는 집합이며 정보와 활동 영역을 규정한다. [용어들 설명, 용어들 설명2]

     

    도메인 분석을 사용하여 마이크로 서비스 모델링

    이때 컨텍스트에 따라 도메인이 달라진다.

    예를 들어 개발과 배포가 있다면 개발에서 생각하는 서버(실행될 대상)와 배포에서 생각하는 서버(배포를 계획할 대상)가 같을까요?

    또한 배포라고 할지라도 대기업급의 스케일링이 필요한 배포와 스타트업의 배포, AI 서비스와 블로그 서비스의 배포가 같을까요?

    모두 컨텍스트에 따라 개발할 도메인이 달라지게 되는 겁니다.

     

     

    각 도메인은 모두 같은 유비쿼터스 언어로 통일하여 사용해야 합니다.

    같은 개념을 다른 용어로 사용하거나 다른 개념을 같은 용어로 사용하는 일을 막기 위해서이다.

     

     

    각 도메인을 설계할 때는 의존성에 따라 레이어를 나누어 설계를 하는게 좋다. [The Clean Architecture, Implementing Domain Driven DesignDomain-Driven Hexagon]

     

    구현을 해서 고전적인 아키텍쳐 표현방식으로 시각화한다면 이런식이 되겠죠.

     

    Domain Driven Design–Structuring your applications, Great Diagram about our DDD NLayered .NET 4.0 Architecture

     

     

    자, DDD를 러프하게 정리하자면 이렇습니다.

    1. 사용/개발자에 따라 도메인과 컨텍스트를 나눈다.
    2. 같은 컨텍스트 내에서는 동일한 언어를 사용한다.
    3. 도메인을 설계할 때는 의존성에 따라 레이어를 나누어라.

     

    이렇게 DDD를 이용한 설계를 적용하게 되면 다음과 같이 변화하게 되겠죠.

    OOP vs DDD [Domain-Driven Design vs. anemic model. How do they differ?]

     

     

    DDD의 실제 구현에 있어 도움이 될만한 패러다임이 있다.

    각 도메인에 따라 구현을 하게 될텐데, 다음과 같이 겹치는 영역이 생겨나게 된다.

    AOP 입문자를 위한 개념 이해하기

    이때 AOP는 관심사 분리를 하여 공통되는 기능을 모으고 DI(Dependeny Injection)을 통해 사용할 수 있게 만들어줄수 있는 패러다임이자 도구이다.

     

    +.

    원글에서 나왔던 Rosch 의 프로토타입 이론은 만들어지는 제품 산출물은 어떠한 형태를 갖추어야 하는가에도 적합한 이론이라고 생각한다. [MVP와 PoC, Prototype, Pilot 차이, Top 5 Biggest Challenges when Building an MVP and how to Avoid Them]

     

    Proof of Concept vs. Prototype vs. MVP: Journey to Product Market Fit

    • 개념증명: 아이디어가 실현 가능성이 있는지 확인
    • 프로토타입: 미완성 버전이나 중요한 기능들이 포함되어 있어야 함
    • MVP: 최소 실행제품으로 생존하기 위한 최소한의 노력과 완성도가 있어야 함

    프로토타입을 제작함에 있어 중요한 기능은 디자이너, 개발자, 재무담당등 다양한 사람들의 관점에서 모두 달라질 수 있다.

    많은 사람들이 중요하다고 생각되는 제품의 유사도에 따라 전형적인 제품을 만드는 것이 프로토타입의 요건이라 생각합니다.

    Class 8: Semantics & Prototype theory

    • 모두 공유하는 속성이 없을수도 있다
    • 다른 구성원과 공유하는 속성이 많다면 유사도가 높다

     

    그렇지만 제작할 때 모두가 공유하면 좋을만한 컨텍스트가 있다.

    서로 생각하는 프로토타입이나 MVP가 다르다면 유사도가 제대로 측정되지 않을 것이기 때문이다.

     

    사용가능하고, 최종적인 형태와 유사하게 만들어져야 한다

    사용가능하고 최종적인 형태와 유사해야 한다는 것.

    사용 가능하지 않다면 MVP에서 핵심인 "생존가능" 자체가 불가하며, 최종적인 형태와 다르다면 "설계변경" 비용이 클 것이기 때문이다.

     

    객체지향과 존재

    지금까지 주제를 확장해 다양한 추상화와 철학적 탐색, 좋은 설계와 철학이란 어떤것인가를 주로 다루었다.

    다시 본론으로 돌아올 차례이다. [보편자 실재론의 존재론, 아리스토텔레스의 존재론, 아리스토텔레스의 보편자 이해와 개별주의 실체관]

     

    시작했을 때를 리마인드 해보자.

    클래스와 프로토타입의 가장 큰 차이는 인스턴스 이전에 존재하였는가 이다.

    비슷한 점은 객체지향으로서 어떠한 존재(무엇)을 설명하기 위해 본질을 찾으려 한다는 점이다.

    존재론에서 탐구하려는 것은 어떠한 것이 있다면 무엇이며, 어떻게 존재할 수 있는가이다.

     

    여기 2개의 존재가 있다.

    소크라테스는 사람이고 철학자, 나는 사람이고 개발자다.

    소크라테스와 나는 개별자[개별적 존재]이며, 사람은 보편자[보편적 존재]라 할 수 있다.

    그렇다면 개별자와 보편자는 어떤 관계일까?

     

    우선 각 개별자는 나타났다가 사라지는 존재임이 분명하다.

    그러나 보편자는 다소 모호한 점이 있다.

     

    사람은 어떠한 일로 멸종할 수도 있다.

    사람이란 보편자는 단지 실재하기 때문에 존재하는 것일까? 아니면 근본적인 성질이라 할 수 있는가?

    수라는 보편적인 개념은 단순히 지운다고 사라지는 것일까? 사라지는게 아니라면 절대적으로 존재하는 걸까, 아니면 실재 값들이 있기에 존재하는 것일까?

    (보통 존재하지 않는 수라고 오해하는 허수도 $i^2 = -1$ 를 보듯 실재적인 값이 존재함이 명확하다.)

     

    플라톤의 이데아론 아리스토텔레스의 실체론이 갈리는 부분이다.

    Plato and Aristotle: How Do They Differ?

    플라톤은

    • 보편적 성질은 불변하며 실재함 [이데아]
    • 보편자는 개별자로 나타난적 없지만 존재가능
    • 개별자는 보편성을 일부 결여된채로 존재 [이데아가 아니므로]
    • 개별자는 결여는 되었지만 닮았고, 생성/소멸이 일어남

     

    아리스토텔레스는

    • 개별자란 개체만이 근본적인 실재이며 실체임 [실재는 현존, 실체는 근본이라 이해하면 됩니다]
    • 개체들은 불변이 아니며, 질료와 현상의 결합임 [질료는 대리석이고 형상은 조각모양]
    • 보편자는 유종관계(상하/포함관계)에서 나타나는 표상임 [보편자가 제1 실체라면 개별적 차이성이 없어지며 모순]

    라 주장하였다.

     

    Aristotle's theory of universals

    이쯤되면 무언가 떠오른게 있는가?

    그렇다 클래스(이데아)와 프로토타입(실체론)이다.

    한번 비교를 해볼까요?

     

    클래스

    • 클래스 자체의 성질은 불변하고 실재한다.
    • 클래스는 객체로 나타난적이 없어도 존재가능
    • 인스턴스 객체는 값이 존재함으로서 보편성을 일부 잃는다
    • 객체는 결여되었지만 닳았고, 생성/소멸이 일어남

     

    프로토타입

    • 객체만이 근본적인 실재이며 실체임
    • 객체들은 불변이 아니며, 값과 타입의 결합임.
    • 프로토타입은 유종관계에서 나타나는 표상임.

     

    나는 이러한 관점에서 클래스와 프로토타입은 각각 이데아론과 실체론에 가깝다고 생각한다.

     

    플라톤과 아리스토텔레스의 시대가 끝나고 파생된 떡밥으로는

    보편자가 실체로 존재하는가, 단지 이름일 뿐인가로 싸우게 된 보편논쟁이 있다. [보편 논쟁, 보편과 특수]

    신의 존재와 직결되는 문제라 한참을 싸웠다고..

     

    지금도 관념/실재론등으로 완전한 결론이 났다고 말하기 어려우니 여러분의 선택에 맡기겠다.

    어떤 세계관이 마음에 드십니까?

    피곤해서 빨리 끝


    의식의 흐름대로 작성해서 그런지 계기의 글과는 완전히 다른 주제의 글이 된 것 같다.

     

    원본 글은 스코프 문제가 가장 흥미로웠는데..

    비슷한 이유에서인지 다른 프로토타입 기반 언어들도 self를 쓰면 다이나믹 스코프가 기본인 모양이다. 

    // io
    someValue := "hello"
    outerFunc := method(self someValue)
    obj := Object clone do (
      someValue ::= "world"
      outerFunc ::= outerFunc
    )
    
    outerFunc     // hello
    obj outerFunc // world

     

    # Perl
    $someValue = "hello";
    sub outerFunc {
      return $someValue;
    }
    sub dynamicScope {
      local $someValue = "world";
      return outerFunc();
    }
    
    print outerFunc();    # hello
    print dynamicScope(); # world

     

    개인적으로는 Lexical scope가 Dynamic scope보다 이해하기 쉽고, 버그도 적을거라 생각하여 선호한다.

    자바스크립트 화살표 함수나 io의 block 등을 생각하면 이제 스코프는 선택문제 아닐까 ㅎㅎ

     

    음..... 쉽게 설명하려 쓸려했더니 괜히 어려운 소리만 늘어놨는지 모르겠다....

    이 글을 읽고 프로그래밍 지식이 늘었거나, 철학적 주제를 알게 되었거나 무언가 도움이 되었으면 하는 바램이다.

    나중에 시간이 난다면 인식론/존재론을 기반으로 약간 더 보충해보고 싶기도.

     

    2021 출판사 대표들이 뽑은 올해의 책, 소쉬르의 일반언어학 강의도 읽어보고 싶다아~~~~

    비교적 최근에 나온 이론 같은 객체지향 철학도 한번쯤 알아보면 좋을것 같구.

    댓글

Designed by black7375.