객체지향에 대한 다양한 의견들

냥린이·2021년 12월 2일
0

객체지향

목록 보기
1/2

들어가며

지난 몇 년 동안 Java를 필사적으로 피해다녔다. 한국에서 취업하려면 spring을 해야한다는 걸 알고 있었지만, 이유 모를 심리적 거부감이 있었다.

왜 Java를 싫어했나? 저학년 때 객체 지향 프로그래밍 수업 (사실상 개념 던져주기와 자바 실습 수업)을 들었는데 다형성이나 상속이니 진정으로 와닿지 않고 재미가 없었다. 내가 짠 코드가 진정으로 객체 지향적인지 확신할 수 없었고 시간이 지날수록 객체가 뭔지 더 헷갈렸다. 프로그래밍 언어론을 제일 먼저 듣고 혼자 코딩 경험치를 쌓은 후에 객체 지향 수업을 들었다면 좀 더 이해가 빨랐을까? (비단 이 이유가 아니더라도 프로그래밍언어론 수업을 막학기에서야 수강할 수 있었던 건 너무 아쉽다.. 복전생의 서러움ㅜㅜ)

아무튼 Java를 막연히 피하고 싶은 마음에 그리고 시간에 쫓겨 프로젝트를 빨리 마무리하기 위해 Node.js, flask, django를 돌아가면서 써왔지만 더이상 현실을 외면할 수 없어진 지금! 다시 Java와 객체지향에 손대보기로 마음 먹었다. 겨울에 인턴을 프론트엔드로 하기로 해서 개인 공부 시간이 얼마나 날지 모르겠지만 틈틈히 해보려고 한다.

객체 지향 프로그래밍 (Object-Oriented Programming)

OOP는 프로그래밍 패러다임 중 하나로 프로그램을 구성하는 기본 요소는 Object이며 프로그램 객체들이 상호작용하는 것이 프로그램이라고 보려는 관점이다. (왜 관점이냐면 사실 객체 지향 프로그래밍 스타일로 코드를 작성해도 결국 low 레벨에서는 imperative/procedual하게 돌아갈 수 밖에 없기 때문이다. 그리고 더 엄밀히 따지면 근본적으로는 functional하게 돌아간다.)

객체지향은 객관성이 많이 떨어지는 분야로 모두가 동의하는 정의와 방법론이 없다. 왜냐면 기계가 아닌 사람처럼 객체를 인지하고 생각하는 전제 자체가 개인마다 다르게 받아들여질 여지가 많기 때문이다. 절차적 프로그래밍은 기계와 근접하여 객관적인 반면 객체 지향 프로그래밍은 상당히 주관적이다.

그래서 실무에서 주로 사용되는 주류 이론을 중점적으로 익히는 것이 효율적이지만(시니어 개발자의 팁을 전수 받는다는 느낌으로), 수십 년간 등장했던 소수설의 입장도 한번쯤 정리해 볼 가치가 있다. 이때 조심해야 하는 게 중심을 잃고 흔들리는 것인데, 여러 이론 속에서 헷갈릴 때 데이터로 증명할 수 있는 방법을 따르는 것이 객관성을 높이는 과학적 사고방식으로 접근하자.

아 벌써 하기 싫은데.. 과연 이 시리즈를 완성할 수 있을 것인가 ㅎㅎ 변명처럼 들리겠지만 내 마음을 대변하는 글을 발견해서 걸어둔다..

OOP를 빨리 잊을수록 여러분과 여러분 코드에 좋습니다

고민할 영역

  • 프로그래머의 효율을 늘리는 법
  • 프로그래머의 실수를 줄이는 법

학계와 실무의 차이

우리가 사용하는 주류 언어(C/C++, C#, Java)는 대부분 업계의 작품이다.
현업에 종사 중인 사람과 그렇지 않은 사람들은 객제 지향 설계 시 다른 경향을 보인다.

C는 기계와 가까운 언어이므로 주관적 이론이 추가될 여지가 많지 않지만, 객체지향은 업계에 몸담지 않고 실질적으로 프로그래밍 경험이 부족한 사람들도 다양한 의견을 개진했다. (그러나 학계에서 작은 규모로 실험하여 논문화 시킨 내용이 중대형 실무 프로젝트에는 부적합한 경우가 많았다.) 앞서 설명했듯 Object-Oriented Programming 의 주관성 때문이다. 그러나 프로그래머는 공부를 많이 한 사람일수록 남의 의견을 진지하게 검토해보는 경향이 있어 본인이 공부를 잘 해왔음에도 불구하고 의심 속에 시간 낭비하는 경우가 많다.

Java

'Java는 객체지향, 객체지향은 Java'를 공식처럼 외우는 사람이 많은데 Java가 반드시 객체 지향 프로그래밍만 가능한 언어는 아니다. 언어와 스타일은 1:1 매핑되는 개념이 아니며 오히려 프로그래머의 배경이나 성향에 따라 달라진다. 어셈블리어나 C부터 시작하면 절차적으로 작성하는 경향이 있고, Java부터 시작한 사람은 C++도 객체 지향적으로 작성한다. 그리고 언어 불문 내공이 깊으신 분들은 javascript, python에서도 functional하게 코드를 짜신다. 유독 Java가 객체지향 스타일로 많이 쓰이는 것은 Java가 모듈로 묶는 것을 추구하고 메모리 관리를 안 하다보니 같은 데이터를 공유하지 않는다는 점, 기능별로 구현한다는 점이 객체 지향과 궁합이 잘 맞기 때문이다. (객체 지향은 과거 상대적으로 넉넉한 하드웨어 성능에 비해 부족한 소프트웨어 성능에 대한 해결책으로 등장한 방법이다.)

Java의 개발 배경

웹 백엔드의 터줏대감인 Java는 사실은 소형 임베디드 시스템에 사용하기 위해 만들어졌다. 기존 언어(C)는 디바이스, OS의 플랫폼마다 새롭게 컴파일을 해야하는 번거로움이 있었기 때문에, 한 번만 빌드하면 어떤 플랫폼에서든 작동하는 언어인 Java를 만들게 되었다. 그러나 인터넷이 부흥하면서 웹 개발로 방향을 바꾸어 대중화가 되었고 현재까지도 인기가 많은 매니지드 언어로 자리하고 있다.

매니지드 언어란?
메모리 관리에 신경을 덜 써도 된다. (C, C++과 반대)
기계에 아주 가깝지 않은 개념을 코드로 옮겨 사용하기에 적합하다.

실행 모델

Java는 크로스 플랫폼이기도 하고 아니기도 하다.

크로스 플랫폼이란?
특정 언어로 작성한 코드를 여러 플랫폼에서 실행할 수 있다.
여러 디바이스와 운영체제에서 실행 가능한 소프트웨어이다.

위와 전통적인 컴파일 방식에서는 소스코드를 각각 컴파일러와 어셈블러를 통해 오브젝트 코드로 변환하고, static/dynamic linking 과정을 거쳐 최종적으로 실행파일로 만든다.

C로 작성한 소스코드는 진정한 크로스 플랫폼라고 할 수 있다. C가 컴파일 되지 않는 디바이스는 거의 없기 때문이다. 그러나 그것이 컴파일 되어 나온 실행 파일은 플랫폼 dependent 하므로 크로스 플랫폼이라고 보기 어렵다.

그러나 Java는 전통적인 컴파일과 달리 기계어 코드가 아닌 바이트 코드로 변환한다.

바이트 코드란?
하드웨어가 아닌 가상 머신에서 돌아가는 이진 코드 실행 파일이다.
하드웨어 종속성을 줄이고 인터프리터로 처리된다.

바이트 코드로 컴파일하는 게 무슨 의미가 있는지 적기 전에 Java의 컴파일 방식을 잠시 살펴보고 지나가겠다.

JDK

Java는 Interpretive Compilers를 사용한다.
Java는 Java Development Kit(JDK)를 통해 소스코드를 컴파일한다.
Java Development Kit는 Javac.exeJava.exe로 구성되며,
Javac.exe는 소스코드(.java)를 바이트 코드(.class)로 변환하여 JVM에 빌드하는 컴파일러이고
Java.exe는 JVM에서 바이트 코드를 실행시키는 인터프리터다.

JRE

JDK를 다운 받으면 호환되는Java Runtime Environment(JRE)가 함께 설치된다. JDK 안에 JRE가 있고 그 안에 JVM이 들어 있는 형태라고 이해하면 편하다.

JRE는 Java가 크로스 플랫폼이다! 라는 주장의 근거가 된다. JRE는 추상화의 전형적인 사례로, 기반 운영체제를 자바 애플리케이션 실행을 위한 일관적인 플랫폼으로 추상화하기 때문이다.

소프트웨어 프로그램을 실행하기 위해서는 실행할 환경이 필요하다. 런타임 환경이란 다른 소프트웨어를 실행하기 위해 고안되는 일종의 소프트웨어로 프로그램 실행을 위해 클래스 파일을 로드하고 메모리 및 기타 시스템 리소스에 대한 액세스를 확보한다. 과거에는 대부분의 소프트웨어가 운영체제를 런타임 환경으로 사용해서 운영체제와 디바이스에 종속적일 수 밖에 없었다. Java는 JRE라는 자바 전용 런타임 환경을 구축하면서 패러다임을 바꿔놓았다.

WORA(Write Once, Run Anywhere)
'한 번 작성해서 모든 곳에서 사용한다'는 JAVA의 기본 원칙이다.

JRE는 자바 클래스 라이브러리(Java class libraries)와 자바 클래스 로더(Java class loader), 자바 가상 머신(Java Virtual Machine)로 구성된다.

클래스 로더는 올바르게 클래스를 로드해 코어 자바 클래스 라이브러리에 연결하는 역할을 하며, JVM은 자바 어플리케이션이 디바이스 또는 클라우드 환경에서 실행되는 데 필요한 리소스를 확보하도록 보장하는 역할을 한다.

JVM은 라이브 자바 프로그램 실행을 담당하는 실행 소프트웨어 시스템이고 디바이스에 따라 다르다. 따라서 Java의 플랫폼은 사실 JVM 이라고도 말할 수 있다.

JRE는 자바 코드를 받아서 필요한 라이브러리와 결합한 다음 이 코드를 실행할 JVM을 시작하는 온디스크 시스템이다. JRE는 앞서 설명한 구성 요소들을 담는 컨테이너이며 각 구성 요소의 활동을 조율하는 역할을 하는 일종의 메타 운영체제이다. 자바 프로그램이 거의 모든 운영체제에서 수정 없이 실행될 수 있도록 하며, 프로그래머가 메모리 할당과 재할당을 수동으로 조작할 필요 없도록 자동 메모리 관리를 제공한다.

JIT

JIT(Just-In Time) Compiler는 실시간 컴파일러로, Java의 성능을 C와 견줄 만큼 끌어올린 장본인이다.

앞서 바이트 코드를 인터프리터로 실행한다고 했지만, 필요에 따라 실행 직전에 JIT 컴파일러에 의해 기계어로 번역되기도 한다. JIT를 사용하면 실행 전 지연시간이 발생하지만 인터프리터보다 높은 성능을 제공한다. 자주 반복 사용되는 코드를 네이티브 코드로 미리 컴파일해두면 최초 실행 시에는 추가 시간이 소요되겠지만, 그 이후부터는 훨씬 빠르게 실행이 가능하기 때문이다.

이렇듯 JVM의 JIT 엔진은 프로그램 동작을 기반으로 런타임에 루틴을 최적화해서 사전 컴파일되는 C에서는 불가능한 다양한 종류의 최적화를 실현한다.

그 외

그 외에도 Java의 메모리 관리, 가비지 컬렉션 등 Java에 대해 설명할 게 있지만 그건 따로 글을 파서 정리하려고 한다. Java를 끝장 내버리고 싶다면 직접 Java Specification 문서를 탐독하는 것을 추천한다! 문법 관련된 글도 따로 작성해봐야겠다. 일단 여기서 마무리.

참고자료

POCU Labs

Modern Programming Laguages - Webber Brooks

자바 런타임 환경의 이해

OOP와 PP

profile
홀로서기 기록장

0개의 댓글