좋은 코드란 무엇일까?
프로젝트를 반복하고, 서비스를 만들면서 반복되는 코드들을 타이핑하면서 생각하고 궁금해졌다. (몸으로 체감한 궁금증)
"좋은 코드는 무엇이고 어떻게 만드는 걸까? 지금 내가 작성한 코드들에서 서비스가 변경되고 확장되면, 새로운 기능에 맞춰서 전체적인 부분을 살펴봐야 하고, 또 오류를 수정하고 이런 일을 반복하면 너무 힘들 것 같은데... 이게 맞나?" 머릿속에서 드는 생각은 현재 내가 작성하는 방식의 코드가 좋은 코드에 충족하지는 않은 것 같았다. 그래서 이참에 제대로 좋은 코드에 대해 학습해 보았다. 이 글의 목적은 "아하, 이런 느낌이구나"를 공유하는 데에 있다.
아래의 세 가지 정도의 기준을 만족하면 좋은 코드라고 할 수 있을 것 같다.
- 변경사항을 쉽게 반영 할 수 있는가?
- 일정한 기준으로 나누고 묶어서 정리가 되어 있는가?
- 대부분의 사람들이 쉽게 이해할 수 있는가?
결론적으로 쉽게 이해가능하고 변경할수 있으면 좋은 코드이다. 너무나도 당연한 말인것 같지만 이 문장을 제대로 받아들이고 나서 왜 객체지향이 필요한지, 혹은 여러 가지의 디자인 아키텍처가 탄생했는지 체감할 수 있었다.
Object Oriented Programming : 여러 부품이 모이면, 하나의 멋진 자동차가 된다
위에서 내가 한 고민들을 이미 훌륭한 프로그래머 선조들께서 더욱더 심오한 고찰을 통해 많은 방식으로 해법을 정리해놓으셨다.
그중 오늘날 가장 널리 쓰이는 프로그래밍 방식인 객체지향에 대해 이해해 보았다.
내가 처음 프로그래밍을 시작할 때 객체지향에 대해서 아무리 설명을 들어도 크게 아하! 하면서 이해한 적이 없었다. 무엇인가 꽉~ 막힌 느낌이었다. 이제 와서 생각해 보니 그 이유를 알 것 같기도 하다. 사람의 학습은 자신이 경험한 것을 비교하면서 이루어진다고 한다. 당연히 내가 알고 있는 프로그래밍 배경지식이 많지 않다 보니 이해할 수 없었던 것이었다.
절차적 프로그래밍은 OOP의 라이벌?
우선, 느낌으로만 보면 객체지향의 반대에 있는 것 같은 절차적 프로그래밍을 알아보자. 프로그래밍을 시작한 분들이라면 한 번쯤은 들어봤을 것이다.
절차적 프로그래밍 "Procedural Programming" 소리 나는 대로 읽어보면 프러시저 프로그래밍. 프로시져 = 함수 즉, 함수를 통한 프로그래밍이다. 절대 순서대로 실행되는(순차적인) 프로그래밍이 아니라는 사실을 알고 가야 한다.
절차적 프로그래밍은 필요한 기능 함수의 절차적인 실행으로 진행되며, 코드(함수)의 재사용성이 좋고, 코드의 흐름을 이해하기 쉬운 장점이 있다. 대표적으로, 알고리즘 문제를 해결할 때 많이 쓰는 것 같다.(내가 평소에 알고리즘을 풀 때 많이 접한다는 이야기이다.) 객체지향 프로그래밍이 인기가 많아지기 전 대부분의 프로그래밍 방식은 컴퓨터의 사고인 절차적 프로그래밍으로 구성되어 있었고, 이것이 인간중심이 강한 객체지향 프로그래밍이 등장하면서 서로 대척점에 있는 반대 개념처럼 느껴지게 된 것이다. 사실 두 프로그래밍은 그냥 다른 방식의 프로그래밍 기법이다. 마지막으로, 객체지향 프로그래밍 이름에서도 알 수 있듯이, "지향" 한다라는 것이다. 프로그래밍은 컴퓨터가 이해할 수 있도록 어쩔 수 없이 기본은 절차적인 것 같다. 절차적인 코드도 존재하지만 객체 중심의 역할을 더욱 잘 살리는 방식으로 코딩하는 것이 "객체지향적 프로그래밍"이구나 이해했다.
그렇다면 왜 절차적 프로그래밍에서 객체지향 프로그래밍으로 프로그래밍의 패러다임이 이동했을까?
Why OOP?
결론부터 말하면 사람을 위해서라고 이야기할 수 있을 것 같다. 과거에는 지금처럼 큰 규모의 소프트웨어와 하드웨어가 존재하지 않았고, 그에 따라 엄청~ 복잡한 절차적 프로그래밍이 나오는 경우가 많지 않았다고 한다. 그래서 사람이 코드를 읽고 이해하기 문제가 없다고 이야기한다. 벌써 뒤에 나올 이야기의 내용이 유추되지 않는가? 기술의 발전을 통해 소프트웨어는 또한 점점 복잡해지고 거대해졌고, 기존의 절차적 프로그래밍 방식으로 코딩을 하다 보니, 흐름을 이해하기도 쉽지 않고 유지보수는 더욱더 힘든 일명 "스파게티 코드"가 발생하니, 다른 방식의 해법이 절실했던 것이다. 실행은 컴퓨터가 하지만 결국 설계와 작성은 사람이 하는데 사람이 이해를 할 수 없는 코드를 짤 수 없지 않은가.
객체지향의 특징을 Chatgpt에게 물어보았다.
객체지향 프로그래밍(OOP, Object-Oriented Programming)은 소프트웨어 개발 패러다임 중 하나로, 프로그램을 객체(Objects)로 구성하고 이러한 객체들 간의 상호 작용을 중심으로 프로그래밍하는 방식을 의미합니다. 객체지향의 주요 특징은 다음과 같습니다:
객체 (Objects): 객체는 현실 세계의 엔티티를 모델링한 것으로, 데이터와 해당 데이터를 처리하는 메서드(함수)를 포함합니다. 예를 들어, 자동차, 고객, 주문 등과 같은 객체는 속성과 행동을 가지고 있습니다.
클래스 (Classes): 클래스는 객체의 설계도 또는 템플릿 역할을 합니다. 클래스는 객체를 생성하기 위한 구조와 행동을 정의합니다. 객체는 클래스의 인스턴스(Instance)입니다.
캡슐화 (Encapsulation): 캡슐화는 객체의 데이터와 관련 메서드를 하나의 단위로 묶어 정보 은닉을 제공합니다. 이를 통해 데이터를 보호하고 객체 외부에서 직접 접근하지 못하게 합니다.
상속 (Inheritance): 상속은 기존 클래스에서 새로운 클래스를 파생시키는 메커니즘으로, 코드 재사용을 촉진하며 계층 구조를 형성합니다. 파생 클래스는 기존 클래스의 특성을 상속받고 확장할 수 있습니다.
다형성 (Polymorphism): 다형성은 같은 이름의 메서드나 함수가 다른 형태로 동작할 수 있도록 하는 기능을 말합니다. 이는 메서드 오버로딩과 메서드 오버라이딩을 통해 구현됩니다.
메시지 패싱 (Message Passing): 객체들 간의 상호 작용은 메시지를 주고받는 것으로 이루어집니다. 객체는 다른 객체에게 메시지를 보내고, 해당 메시지를 처리하는 메서드가 실행됩니다.
모듈화 (Modularity): 객체 지향 프로그래밍은 코드를 모듈화 하여 유지보수와 재사용을 촉진합니다. 각 객체는 독립적으로 개발하고 테스트할 수 있으며, 시스템을 여러 모듈로 분할하기 용이합니다.
객체지향 프로그래밍은 복잡한 시스템을 더 쉽게 이해하고 관리할 수 있게 해 주며, 현실 세계의 모델링에 적합한 패러다임입니다. 이러한 특징들은 코드의 가독성을 향상하고 유지보수를 용이하게 만들어 개발 프로세스를 개선하는 데 도움을 줍니다.
너무 어렵다. 하지만 지금 내가 하는 말을 이해하면 자연스럽게 위의 개념 들고 이해가 될 것이다. 객체지향의 본질은 아래와 같다.
작은 단위의 독립적인 역할과 책임을 수행하는 객체(부품)가 모여 소통하면서,
하나의 크고 복잡한 작품(서비스)을 만들어 낸다.
내가 이해하고 받아들인 객체지향을 한마디로 정의하자면 위와 같이 말할 수 있다. 단어를 잘 살펴보면 gpt가 설명해 준 개념이 고스란히 녹아져 있다.
작은 단위의 독립적인 = 객체
소통 = 메세징, 인터페이스
모인다 = 바인딩
바탕화면 폴더를 정리하지 않으면, 어떤 파일을 찾을 때 하나하나 제목을 보면서 찾는 수고스러움을 느낄 것이다. 이것의 해결법은, 동일한 주제별로 카테고리화시켜 폴더를 생성하고 그 안에, 비슷한 성질의 파일들을 묶어서 보관하고, 폴더제목을 성향의 특징에 맞게 보자마자 "아! 이런 거 있는 폴더구나"할 수 있도록 만들면 될 것이다. 이 작업을 프로그래밍에서 똑같이 해주면 객체를 독립적으로 생성해 주고 추상화 작업을 마쳤다고 할 수 있다. 또한 파일의 내용을 쉽게 변경하면 안 되는 것들에 비번을 걸어 놓듯이, 프로그래밍에서도 객체 안의 데이터에 접근해서 쉽게 변형할 수 없도록 보호한다라는 개념에서 캡슐화를 해주면 된다.
이렇게 캡슐화된 객체들이 잘 소통할 수 있도록메세징을 주고받게 하는 인터페이스(호환성)를 잘 설계한다면, 기존의 소프트웨어를 변경하고 이해하는 것이 수월해지는 장점을 가질 수 있다. 마지막으로, 동적 바인딩이 중요하다. 상황에 맞게 필요한 기능(부품)을 갈아 끼워서 사용할 수 있도록 해주는 것인데, 일체화된 코드 보다, 프로그램의 유지보수, 확장성에 있어서 압도적으로 유리해진다. 물론 단점도 있다. 처음 설계 시 복잡하기 때문에 조금 더 많은 시간이 필요하고, 오히려 코드가 더 복잡해질 수 도 있다는 것을 주의해야 한다. 개발자는 필요에 따라 상황에 따라 알맞은 것을 선택할 수 있는 자질이 중요한 것을 잊지 말자.
완벽한 코드는 아니지만, 위의 예시를 보면 어떤 식의 차이점이 있는지 알 수 있다.
마무리
내가 공부하기 위해 정리 한 내용이지만, 누군가도 나처럼 아하~! 모먼트를 가지게 된다면 좋을 것 같다. 객체지향이 무엇이고 왜 필요한지 전체적인 큰 그림을 그릴 수 있는 내용의 글이었다. 앞으로 객체지향 설계를 하면서 조금 더 자세한 키워드 내용들을 기록해 보겠다.