현재 서버 아키텍처의 대부분은 객체지향을 베이스로 한 디자인 패턴을 활용하여 구성되어 있습니다. 객체지향이란 것이 어떤 것이며 어떠한 장점을 가지고 있는 것인지 '프로그래밍 언어 패러다임'을 통해 소개하려 합니다.
결국 프로그래밍 언어는 데이터와 명령어로 이루어져 있으며 코드의 중복으로 인한 가독성 저하, 유지보수의 단점을 극복하기 위해 수많은 단위화를 거쳐 지금의 객체지향 프로그래밍이 대세가 되었습니다.
지금부터 프로그래밍 언어의 패러다임
을 처음부터 살펴보고자 합니다.
후에 clean code라는 책을 읽은 후에 다시한번 해당 포스팅을 보완하겠습니다.
맨 처음 프로그래밍 언어가 어떻게 구성되어 있는지부터 살펴보겠습니다.
컴퓨터는 명령어를 처리하는 기계
컴퓨터는 데이터와 명령어 2가지 조합으로 이해합니다.
컴퓨터는 메모리에 저장되있던 명령어를 레지스터로 가져와 제어장치가 이를 읽고 ALU가 연산하여 저장하는 과정을 반복합니다.
더해라 | 메모리 32번지 안의 값과 | 메모리 33번지 안의 값을
저장해라 | 10을 | 메모리 128번지에
명령어는 연산코드
, 오퍼랜드
로 구성되어 있습니다.
연산코드
는 명령어가 수행할 연산을,
오퍼랜드
는 연산에 사용할 데이터 혹은 데이터가 저장된 위치를 의미합니다.
연산코드의 종류들입니다. 이들과 각각 조합되어 코드들이 완성됩니다.
종류 | 연산코드 |
---|---|
데이터전송 | MOVE, STORE, FATCH(LOAD), PUSH, POP |
산술/논리 연산 | ADD, SUBTRACT, MULTIPLY, DIVIDE, INCREMENT(++), DECREMENT(--), AND, OR, NOT, COMPARE |
제어 흐름 변경 | JUMP, CONDITIONAL JUMP, HALT, CALL, RETURN |
입출력 제어 | READ(INPUT), WRITE(OUTPUT), START IO, TEST IO |
컴퓨터가 이해할 수 있게 다음과 같이 번역하면 다음과 같습니다. (위의 명령어를 번역한 것은 아닙니다!)
0101 0101
0101 1101
1100 0011
push rbp
pop rbp
ret
컴퓨터는 위와 같이 0과 1로 이루어진 기계어로 번역된 것만 이해할 수 있습니다.
바로 밑 단락은 사람이 편하게 작업하기 위해 기계어를 영어로 번역한 어셈블리어입니다.
이들의 특징은 컴퓨터가 바로 이해하고 실행할 수 있다는 점입니다. 그래서 이를 저급 언어
라 부릅니다.
언어 | 설명 | 컴퓨터 이해 여부 |
---|---|---|
저급 언어 | 컴퓨터가 바로 이해하고 실행할 수 있는 언어 | O |
고급 언어 | 사람이 이해하고 작성하기 쉽게 만든 언어 | X |
코드의 흐름과 순서에 기반하는 것
모든 프로그램 코드는 위에서 설명한 기계어로 이루어져 있으며 CPU는 이를 순서대로 읽습니다.
이것이 첫번째 패러다임입니다.
구조라는 개념은 아직 없을 때라, goto문으로 주소 왔다갔다를 시전하여 정작 하라는 코딩은 못하고 흐름만 신경써야되는 경지에 이릅니다.
일명 스파게티 코드
라 불리는 복잡한 코드가 되어 개발자가 이해하기 매우 힘들고 난해한 구조를 띄게 됩니다.
명령어의 양이 많아지고 특정 코드 부분이 어디에 사용되는 코드인지도 알지 못하고 흐름 파악도 안됩니다.
사람들은 중복, 흐름파악의 문제를 해결하기 위해 단위화할 방법을 찾기 시작하였고 그렇게 프로시저
라는 개념이 등장합니다.
프로시저 콜(함수 호출)을 통해서
추상화와 재사용성
을 얻는 것이 본질입니다.
단순히 순차적인 명령 수행(데이터 + 명령어)
이 아닌 프로시저
(Procedure, 루틴, 서브루틴, 메소드, 함수 등)를 이용한 프로그래밍 패러다임입니다.
사실 절차적이라는 번역은 오역에 가깝습니다. Procedural
의 본 의미는 절차가 아닌 프로시저의 의미이기 때문입니다.
하지만 이미 여기저기 많이 쓰이고 있기 때문에 지금까지 쓰이고 있습니다.
C언어는 어셈블리어의 단점을 보완하고자 나온 고급 언어입니다.
UNIX 운영체제를 개발하기 위해 만들어진 언어입니다. 당시 UNIX를 어셈블리어로 개발하던 벨 랩의 케네스 톰슨이 이식성이 좋고 호환성이 좋은 언어를 제작해야겠다는 필요성을 느꼈고 데니스 리치가 B언어를 개조하여 C언어를 만들고 UNIX를 C언어 기반으로 만들게 됩니다.
C언어를 시작으로 다양한 언어들이 C를 기반으로 만들어지기 시작했으며 대표적으로 C++, Java, C# 등이 있습니다.
또한 UNIX와 Linux 기반 운영체제는 지금까지도 C언어로 만들어지고 있습니다.
첫째로 절차지향이라는 표현 자체가 잘못되었고 절차식이란 표현이 옳은 표현이라고 합니다.
'OO지향'
이라는 표현은 단순히 코딩하는 방식
, 프로그래밍 설계방법론
의 차이이며 특정 언어가 OO지향만 지원하는 것은 아닙니다.
C언어 이외에도 모든 언어는 절차를 기본으로 하기 때문에 절차를 지향한다는 표현 보다는 절차이다 라고 말하는 것이 옳지 않을까란 의견이 있습니다.
두번째로 객체지향의 반대가 전혀 아닙니다. 객체지향은 절차식 프로그래밍의 관점이 프로시저
에서 객체
로 확장된 것에 가깝습니다.
프로시저를 사용하게 되면 함수를 호출하는 과정에서 그냥 코드를 실행하는 것보다 훨씬 많은 메모리 접근 비용이 발생합니다.
컴파일러에서 함수를 호출하는 방식이 아닌 코드 자체를 인라인 함수 내의 내용으로 바꾸는 방식을 사용함으로써 이같은 비용이 발생하지 않게 되었습니다.
C++에서 나온 개념이지만 요즘에는 C언어에서도 지원하고 있습니다.
어셈블리어를 대체하기 위해 만들어진 언어이기 때문에 소스코드와 컴퓨터의 동작이 거의 비슷하며 하드웨어 친화적입니다. 이는 이식성이 좋으며 번역하는 비용 제외하면 거의 들지 않습니다.
또한 적은 컴파일러 제한을 통해 유연성이 제공됩니다.
하지만 이는 개발자의 개발 혼잡과 어려움을 가져왔습니다.
유연하지만 그만큼 오류를 잡지 않아서 overflow같은 치명적인 에러가 발생할 수 있습니다.
또한 하드웨어 친화적이라 그만큼 기능이 많고 이해하기 어렵습니다.
프로시저를 통해 구조적으로 코드를 관리함으로써 중복과 흐름파악의 문제점을 해결할 수 있었습니다.
하지만 프로시저라는 것은 추상적입니다.
메모리라는 물리적인 저장장치가 존재합니다. 하지만 프로시저는 메모리에 직접 저장되는 요소들이 아닌, 이를 관리하는 논리적 단위이기 때문에 문제가 발생했습니다.
돈이라는 물리적인 자료형이 있고 이를 더하고 빼는 등의 계산하는 함수 프로시저가 있습니다. 돈 이외에 책이나 연필 등이 추가되고 그에따른 함수들도 각각 추가된다고 가정했을 때 각각의 역할에 맞는 함수를 찾기란 굉장히 힘들것입니다.
이들을 서로 합친 구조가 필요했습니다.
물리적(field), 논리적(method) 요소들을 한대 묶어
높은 수준의 독립성
을 보장
개발자 입장에서 더 쉽고 정돈된 프로그래밍을 할 수 있게 도와주는 프로그래밍 패러다임입니다.
프로그램을 '객체'
라는 기본 단위로 나누고 이들의 상호작용으로 서술하는 방식입니다.
처음에는 이렇게 합친 구조만으로 끝났지만
객체 간의 독립성이란 것이 중요해지면서 이를 더욱 지키는 기술들, 방법들이 지금까지 발전해왔습니다.
대표적으로 캡슐화, 다형성, 상속, 이를 통한 다양한 디자인 패턴들이 발전해왔습니다.
이들은 C언어에 기반하여 만들어진 대표적인 언어입니다.
C언어의 특성은 가져가되 추가로 객체지향 프로그래밍이 가능하도록 설계되었고 이밖에 JVM을 통한 OS 독립적인 실행환경, GC 지원 등이 있습니다.
고급 언어의 특성인 컴파일러와 더불어
나무위키 - 절차적 프로그래밍
나무위키 - 객체지향 프로그래밍
St-lab - 객체지향(OOP)과 절차적 프로그래밍(PP)
Alienus Non diutius - C언어의 유래와 역사
강민철 - 혼자 공부하는 컴퓨터구조 + 운영체제
Minha Ju - C 프로그래밍: 현대적 접근
Kamang - [프로그래밍 패러다임]순차적(비구조적),절차적(구조적),객체지향적 프로그래밍