본문 바로가기
독서/자바,스프링 개발자를 위한 실용주의 프로그래밍

[1-5 상] 1. Object-Oriented

by Thinking 2024. 11. 5.

들어가기에 앞서

특정 라이브러리, 최신 프로그래밍 언어, 인프라 기술은 '기술'이라고 분류합니다. 개발자로서 실질적인 성장을 하고 싶다면 '기술'을 공부하는 것도 아니고, '컴퓨터 공학'도 아닌 '개발'을 공부해야 합니다. 개발을 공부한다는 것은 아래와 같은 키워드를 의미합니다.

 

OOP, 테스트, 아키텍처가 최소 조건이라 생각합니다. 우리는 기술에 집중할 게 아니라 설계나 개발 역량 같은 좀 더 추상적이고, 보편적으로 어디서든 사용할 수 있는 지식을 학습하는 데 집중해야 합니다. 프로그래밍 언어를 학습하는 것 역시 단순히 기술을 학습하는 것이며, 얼마든지 쉽게 증발할 수 있는 기술이라 말하는 것을 이해할 수 있을 것입니다.

 

최신 지식을 꾸준히 공부하는 것은 개발자에게 분명히 필요한 덕목입니다. 하지만 기술은 정말 빠르게 바뀝니다. 중심점 없이 기술만 쫓아가다 보면 깊이를 쌓을 수 없게 됩니다. 한편 객체지향, 테스트 같은 개발 관련 이론은 수십 년간 검증되고, 지금도 중요한 개념으로 남아있는 것들입니다. 

 

이 책에서는 객체지향, 스프링 안티패턴, 테스트, 아키텍처 같은 주제를 다룰 것이며, 특정 지식을 전달하기보다 무엇을 왜 그렇게 해야 하는지 설득하고 이야기를 풀어가는 방식으로 구성했습니다.

 

 

1. 객체지향

순차지향 프로그래밍(Sequential oriented programming)과 절차지향 프로그래밍(Procedure oriented programming)의 차이는 무엇일까요? 순차지향 프로그래밍에서는 코드가 위에서 아래로 순차적으로 실행됩니다. 'Procedure'는 사실 함수입니다. 함수 위주로 생각하고 프로그램을 만드는 패러다임인 것입니다.

 

비즈니스 로직을 객체가 처리하도록 변경한다는 것은 '어떤 요청이 들어왔을 때, 어떤 일을 책임지고 처리한다'라는 책임이 생긴 것입니다.

- 객체에 어떤 메시지를 전달할 수 있게 됐다.

- 객체가 어떤 책임을 지게 됐다.

- 객체는 어떤 책임을 처리하는 방법을 스스로 알고 있다.

 

즉, 데이터 측면에서 봤을 때 어떤 행위를 하기 위해 만들어진 행동과 데이터가 한 곳에 잘 응집됐다고 볼 수 있고, 이를 응집도가 높다고 할 수 있습니다. 객체지향은 가독성보단 책임에 좀 더 집중합니다. 객체들은 각자의 책임을 수행하기 위한 협력 객체가 무엇인지를 알고 있으며, 그 밖에 필요한 값은 모두 각자가 가집니다. 본인이 해야 할 일을 본인이 제일 잘 알게 된 것입니다.

 

협력 객체들의 내부 동작이 어떤지는 알 수 없게 됐습니다. 하지만 믿는 것입니다. 어떤 요청을 했을 때, 이 객체가 알아서 업무를 잘 처리하고, 데이터를 잘 돌려줄 것이라고요. 믿고 있기 때문에, 협력 객체가 '어떻게' 일을 하는지 신경 쓰지 않으며, 제대로 해왔는지만 신경 씁니다. 그래서 캡슐화인 것입니다.

 

클래스와 객체는 그 자체로 온전할 때 다루기 쉬운데, 비즈니스 로직에 필요한 데이터가 잘 모여 있어야만 문제가 발생했을 때 추적하기 쉽습니다. 즉 책임이 중요합니다. 소프트웨어가 달성하려는 목적을 위해 객체들이 책임을 나눠 가져야 한다는 뜻이고, 책임을 기반으로 동작하는 것이 객체지향입니다.

 

 

1.1 책임과 역할

그런데 절차지향이라서 책임을 구분할 수 없을까요? 그렇지 않습니다. 절차지향에서는 함수 단위로 책임을 지면 됩니다. 반드시 객체를 통해서만 책임을 설명할 수 있는 것이 아니라 단순히 책임이 있다고 해서 객체지향이 되는 것도 아닙니다. 책임을 어떻게 나누고, 어디에 할당하느냐, '책임을 함수가 아닌 객체에 할당'하는 것이 중요한 것이죠.

 

그렇다면 '책임을 객체에 할당한다'. 이 한마디로 객체지향을 설명할 수 있나요? 그렇다면 C언어도 객체지향이 될 수 있습니다. 구조체를 만들고 함수 포인터로 구조체에 함수를 넣으면 구조체 단위로 책임을 할당할 수 있게 되기 때문입니다.

 

반대로 생각해보죠. C언어는 왜 객체지향 언어가 아닐까요? 사실 결정적인 문제가 하나 있는데, C언어 같은 언어에서는 지원하지 못하는 기능이 '추상'입니다. 엄밀히 말하면 객체지향에서는 책임을 객체에 할당하지 않습니다. 객체를 추상화한 역할에 책임을 할당합니다. C언어의 구조체는 추상의 개념을 지원하지 못하고, 이러한 기능을 자연스럽게 지원할 수 없는 C언어는 절차지향 언어인 것입니다. 그래서 객체지향 언어의 특징 중 하나로 다형성이 있는 것이지요.

 

구현과 역할을 분리하고, 역할에 책임을 할당하는 과정을 객체지향에서 중요한 부분입니다. 이 과정으로 큰 장점을 얻게 되는데, 역할을 이용해서 통신하면 실제 객체가 어떤 객체인지 상관하지 않아도 됩니다. 내가 부탁한 책임과 역할을 할 수 있는 객체라면 협력 객체가 구체적으로 어떤 객체인지 신경 쓰지 않아도 된다는 의미입니다. 따라서 확장에도 유연해집니다. 역할에 집중하면서 코드를 크게 변경하지 않고도 기능 확장이 가능하며, 이는 곧 구체적인 Class가 아닌 추상적인 것(역할, Interface)에 집중할 때 유연한 설계를 얻을 수 있게 된다는 뜻입니다.

 

정리해봅시다. 객체가 책임을 갖게 됐고, 객체의 역할이 정해졌고, 어떤 목표를 달성하기 위해 서로 다른 객체와 협력하게 됐습니다. 그래서 객체지향의 본질은 사실 언어나 문법에 있는 것이 아니라 그보다는 '역할', '책임', '협력'이 더 중요하죠.

 

더불어 추상화, 다형성, 상속, 캡슐화도 본질이 아닙니다. 이러한 문법적 기능들은 역할, 책임, 협력을 잘 다루기 위해 존재하는 프로그래밍 언어적 기능일 뿐입니다. 객체지향을 대표하는 기능적인 특징이 될 수 있지만, 핵심이 될 수는 없다는 뜻입니다. 객체지향은 실세계를 반영하는 패러다임이 아닙니다. 오히려 자아를 가진 객체들이 서로 협력하는 방식으로 개발되는 것에 가깝습니다.

 

마지막으로 절차지향에 관한 오해를 풀어보죠. 절차지향은 절대 객체지향에 비해 뒤떨어진 방법론이 아닙니다. 일부 코드에서는 절차지향적으로 작성하는 편이 유리할 수 있음을 인지하세요. 각 패러다임에는 장단점이 있고, 이를 이해하고 문제를 해결하는 데 어떤 방법을 어떻게 사용해야 할지 그때그때 정해야 하는 것입니다.

 

 

1.2 TDA

개발자들이 객체지향적인 사고를 하도록 만들 수 있는 가장 쉬운 방법은 TDA 원칙을 지켜가며 개발하게 하는 것입니다. TDA 원칙이란 'Tell, Don't Ask'의 줄임말입니다. 말 그대로 '물어보지 말고 시켜라'라는 원칙이죠. 단편적으로 얘기하면 TDA 원칙은 무분별하게 사용되는 getter, setter를 줄이라는 의미로 해석될 수 있습니다. getter, setter는 개발자가 객체지향적인 사고를 못하게 하는 방해 요인 중 하나이자 절차지향적인 사고를 하게 만드는 대표적인 원인이기도 하죠.

 

객체는 마치 자아를 가진 것처럼 움직여야 합니다. 단순히 데이터를 나르기 위한 수동적인 존재가 아니며, 능동적으로 움직이는 존재여야 합니다. 그렇다고 객체에게 모든 일을 시킬 수만은 없습니다. getter는 분명 필요한 메서드이며, 객체에게 일을 최대한 시키려 해도 어딘가에서는 협력을 위해 사용해야 하는 상황이 분명 나옵니다.

'독서 > 자바,스프링 개발자를 위한 실용주의 프로그래밍' 카테고리의 다른 글

8. 레이어드 아키텍처  (0) 2024.11.10
[6-11 중] 6. 안티패턴  (2) 2024.11.09
5. 순환참조  (1) 2024.11.09
4. SOLID  (0) 2024.11.09
2. 객체의 종류  (0) 2024.11.05