사람을 사랑한 기술

신 기술은 이전 기술의 어깨를 딛고

이미 있던 것이 후에 다시 있겠고, 이미 한 일을 후에 다시 할지라.
해 아래는 새 것이 없나니, 무엇을 가리켜 이르기를 보라.

이것이 새 것이라 할 것이 있으랴, 우리 오래 전 세대에도 이미 있었느니라.

컴퓨터는 멍청하게도(?) 0과 1만 이해할 수 있다. 그런 컴퓨터를 이용하여 우리는 어떻게 프로그래밍을 할 수 있었을까? 그리고 왜 그토록 많은 언어가 생겼으며 객체지향, 함수지향 같은 개념들이 생긴걸까?

이러한 의문들을 프로그래밍 언어가 발전해온 과정을 통하여 이해하여 보자.

기계어에서 객체지향까지

일단 0과 1이 어떻게 객체지향까지 도달하였는지 알아보자.

기계어

기계어는 0과 1로 이루어진 굉장히 비 인간적인 언어다. 사실 컴퓨터는 우리가 생각하는 것 만큼 똑똑하지 않다. 다만 사람보다 대단히 성실하며 대단히 정확하다.

사람은 숫자라는 개념도 알고, 문자라는 개념도 알고 있다. 정수와 소수를 구분할 수 있으며 머릿속을 쭉 스캔하지 않아도 자신이 모르는 것에 대해서는 모른다고 말할 수 있는 직관이 있다.

더하기 빼기는 물론 곱하기 나누기는 대부분의 사람이 기본적으로 할 수 있다. 조금 더 배운 사람들은 함수나 방정식, 미분, 적분, 기하와 벡터 같은 어려운 개념도 안다.

그러나 컴퓨터는 오직 0과 1 두 가지의 숫자만 이해할 수 있으며 할 수 있는 연산 또한 많지 않다. 다만 컴퓨터는 앞서 말했지만, 대단히 성실하며 대단히 정확하다.

지금 필자의 컴퓨터의 CPU는 3.4 GHz 라는 연산을 할 수 있다. 쉽게 말해서 1초 동안 3,400,000,000(3.4 * 10^9) 번의 연산을 할 수 있다 는 이야기다. 뿐만 아니라 그렇게 많은 연산을 틀리지 않고 정확하게 할 수 있다. 인간은 이런 일이 불가능하다.

성실하고 정확하지 못했던 인간은, 대단히 성실하고 정확한 컴퓨터에게 0과 1로 만들어진 명령어를 전달하여 이를 수행하도록 하였다. 하지만 0과 1로만 이루어진 연산은 인간이 이해하기 어려웠고 정말 머리 좋은 사람이 아닌 이상 컴퓨터를 다루긴 어려웠다.

하지만 사람들은 컴퓨터를 더욱 잘 다루고 싶어했고, 서로 머리를 맞대고 생각하다가 어셈블리어가 탄생했다.

어셈블리어

어셈블리어의 탄생

기계어의 명령들을 일상 용어로 표현하고 기계어가 알 수 있는 기계어로 번역하게 하면 어떨까?

위와 같은 생각에서 출발한 것이 바로 어셈블리어이며, 기계어 명령과 일상 용어를 1:1로 매칭하는 코드표가 만들어졌다.

그리고 그 코드표를 어셈블리어라고 불렀으며, 어셈블리어를 기계어로 번역해주는 소프트웨어어셈블러라고 했다.

하지만 그 당시에 애드삭 유니박 같은 여러 종류의 컴퓨터가 있었고 (지금으로 따지면 Mac과 Window 같은), 어셈블러와 기계어 또한 컴퓨터의 종류 마다 존재했어야 했다.

uml diagram

C 언어

C 언어에는 컴파일러가 존재했으며, C 언어로 작성된 소스코드를 컴파일러가 알아서 각각의 컴퓨터 환경에 맞는 목적 파일을 만들어줬다.

즉, 어셈블리어처럼 각각의 컴퓨터 환경에 맞는 소스코드를 작성할 필요가 없어진 것이다.

uml diagram
-기계어어셈블리어C언어
개발자의 코딩0과 1의 나열일상 단어 사용수학적 기호 사용
소스 파일기종마다 하나씩기종마다 하나씩기종이 몇개든 단 하나
목적 파일(기계어)소스 그 자체어셈블러로 소스를 번역해 생성컴파일러로 소스를 번역해 생성
기계어 비교-기계어와 1:1 대응기계어와 m:n 대응

C++. 객체 지향의 탄생

C언어는 기본적으로 절차적인 형식으로 코드를 작성하게 된다. 절차적인 형식의 문제점은, 인간이 이해할 수 있는 범주의 한계가 있다는 것이다. 왜냐하면 절차적 프로그래밍은 인간이 기계를 조금이라도 더 쉽게 이해할 수 있도록 하는 것에 목적이 있기 때문이다. 천재가 아닌 이상, 절차형으로 엔터프라이즈급의 소프트웨어를 만들고 이를 유지하는 것은 굉장히 어려운 일이다.

그러다가 사람들은 "인간이 왜 기계 종속적인 개발을 해야 하는가?" 라는 의문을 품었고, "우리가 눈으로 보고, 느끼고, 생활하는 현실 세계처럼 프로그래밍을 할 수 없을까?" 라는 고민속에서 객체지향의 개념이 만들어지기 시작했다.

그래서 객체지향은 현실 세계를 프로그래밍에 반영할 수 있게 만들어진 것이다. 그럼 객체지향에서 의미하는 객체, 그리고 클래스는 어떤 의미일까?

Class(클래스)와 Object(객체)

  • Class는 사전적인 의미로 등급, 수업, 종류, 계급, 계층, 분류, 분류하다, 분류되다, 속하다 등의 의미를 가지고 있다.
  • Object는 사전적인 의미로 목적, 대상, 물건 등의 의미를 가지고 있다.

인간은 클래스(Class)고 필자(황준일)는 객체(Object)이다.
이 글을 읽고 있는 당신 또한 인간(Class)의 객체(Object)이다.

그런데 이 책의 저자는 Object(객체)보단 Entity(개체)가 객체지향에서 의미하는 객체의 개념에 더 어울린다고 말하고 있다.

Entity(개체)

개체의 사전적 의미는 다음과 같다.

  • 전체나 집단에 상대하여 하나하나의 낱개를 의미하는 말
  • (생물) 생물 하나의 독립된 생물체. 살아가는 데에 필요한 독립적인 기능을 갖고 있다
  • (철학) 단일하고 독립적인 통일적 존재. 철학 사사으이 발전 과정에서 이 통일성은 물질적/양적 측면, 또는 정신적/질적 측면 따위의 여러 관점에서 고찰되었다.

당신은 어떤게 더 와닿는가? 사실 우리가 개발을 하면서 이해하고 있는 객체에 대한 위의 개념들은 어색하고 부족하다고 느껴진다.

그래서 저자는 객체지향에서 의미하는 객체의 개념을 다음과 같이 해석하고 있다

"세상에 존재하는 유일 무이한 사물"

객체는 상태(state, property)행위(behavior, method)를 가지고 있으며, 상태와 행위에 따라 역할책임이라는 기준으로 코드를 관리할 수 있다.

C++은 C에 앞서 언급한 객체 라는 개념이 추가되어 확장(extend) 된 것이다.

하지만 C++은 객체 지향을 지원하는 것이지 객체 지향이 필수가 아니다. C++에서 main 함수는 클래스의 메소드가 아니다. 클래스가 있어도 돼고, 없어도 된다. printf 함수는 또 어떠한가? 마찬가지로 printf는 함수이며 클래스의 메소드가 아니다. 다만 namespace 라는 개념은 존재한다.

그래서 C++은 정확히 말하면 객체 지향이 아닌 객체 지원 언어라고 할 수 있다.

Java. 진정한 객체 지향 언어

java는 완벽하게 객체 지향 언어이다. 왜냐하면 class가 없이는 무엇도 할 수 없기 때문이다. 자바에서 사용하는 모든 함수는 전부다 클래스의 메소드다. 자바의 main 함수 또한 class에 속해야 한다. 변수를 출력하기 위해서는 System.out.println 이라는 method를 사용해야 한다.

이렇듯 Java는 완벽하게 객체지향을 지원하고 지향한다.

java에는 객체지향이라는 개념 말고도 JVM(Java Virtual Machine) 이라는 개념(혹은 플랫폼) 또한 도입 되었다.

uml diagram

java compiler는 java soure file을 하나의 Class File (Byte Code) 로 만들고, 그것을 각각의 OS에 맞게 만들어진 JRE에 전달되어 JVM에서 실행된다.

-CJAVA
소스 파일11
목적 파일n1
실행Use AnywhereUse Anywhere
비고기종별 컴파일러 필요기종별 JRE, JVM 필요

스프링 프레임워크를 이해하기 전에

Spring Framework

  • 기술이 인간에 대한 완전무결한 사랑을 꿈꾸다
  • 거대함 속의 단순함과 완벽함, 그리고 유연함
  • IoC/DI, AOP, PSA 라고 하는 객체지향의 Best Practice 를 통하여 아무리 거대한 프로그램도 쉽게 구현할 수 있음을 보여준다.
  • 단, IoC/DI, AOP, PSA 안에 녹아든 기술들을 이해할 수 있어야 한다.

앞에서 기계어, 어셈블리어, C, C++, Java 등에 대해 살펴봤다. 즉, 기계에서 실행되는 0과 1이 인간 중심적으로 발전하기 위한 과정을 본 것이다.

Spring Framework는 그 자체로 인간 중심 이라고 봐도 무방할 만큼 현실 세계를 정확히 반영한다. 즉, 객체지향을 정확하고 정교하게 쉽게, 그리고 잘 사용하는 것이 목적이다.
그래서 Spring Framework 이해하기 전에 객체지향의 원칙, 원리, 개념, 디자인 패턴 등을 알아야 한다.

  • 객체 지향의 4대 특성(혹은 원소)

    • 캡슐화(데이터 은닉)
    • 상속(정확히는 확장)
    • 추상화
    • 다형성(내적 일관성, 대체 가능성)
  • 객체지향의 5대 원칙(SOLID 원칙)

    • SRP(단일 책임 원칙)
    • OCP(개방 폐쇄 원칙)
    • LSP(리스코프 치환 원칙)
    • ISP(인터페이스 분리 원칙)
    • DIP(의존 역전 원칙)
  • 디자인 패턴

  • IoC/DI, AOP, PSA

이러한 것들은 Spring Framework 뿐만 아니라 대부분의 Framework가 지향하고 지원하는 개념들이다. 더 정확히는 이런 것이 지켜지도록 강제하여 만든 것이 Framework 라고 할 수 있다.

그리고 여기에 더하여 온전히 Spring Framework를 사용하기 위해 다음과 같은 것들을 알면 더 좋다.

  • JVM에서 실행되는 프로그램의 메모리 구조

    • Stack Frame
    • Heap Frame
    • Static Frame
    • Method Call
  • 자바가 확장한 객체지향

    • abstract
    • final
    • package
    • interface와 implements

JVM(자바 가상 머신)

사실 JVM은 Java 뿐만 아니라 굉장히 다양한 언어에서 사용되고 있다. 앞서 언급 했듯이, JVM만 있다면 단 하나의 목적파일 만 있으면 되기 때문이다. 더불어 이미 만들어진 JVM을 사용하면 되기 때문에 더더욱 JVM을 사용하는 것이 효율적이다.

Spring Framework는 객체지향이라는 철학 위에 쌓아 올린 제품이다. 그렇기 때문에 Spring Framework를 잘 사용하기 위해선 객체지향이라는 것을 더욱 더 정확하게 이해하고 알아야할 필요가 있다.

Last Updated: