CS 상식/디자인패턴

객체 지향 프로그래밍(OOP): 내 방식대로 개념 적용해보기 - feat. 객체지향의 사실과 오해 책 리뷰

SparkIT 2024. 11. 11. 19:18

개발을 공부해 본 사람은 한 번쯤은 듣게 되는 객체 지향 프로그래밍(Object-Oriented Programming, OOP). 굉장히 친숙하면서도 정확히 이해하기에는 모호한 개념이라고 생각하는데요. 이를 더 깊이 이해하기 위해'객체지향의 사실과 오해: 역할, 책임, 협력 관점에서 본 객체지향'이라는 책을 읽고 나름대로 느낀 점들을 정리해보려 합니다.

 

 


'객체지향의 사실과 오해' 리뷰

우선 내용을 전체적으로 요약하지는 않을 것입니다. 모든 내용이 하나하나 정확히 기억나지는 않을뿐더러, 전체적으로 코드 수준에서 명확하게 설명하는 방식보다는 추상적이고 모호한 형태로 설명하는 방식이 주로 사용되었다고 생각해 내용을 요약하는 것이 크게 도움이 되지 않다고 생각하기 때문입니다(개인적인 생각입니다)... 그래서 저는 기억에 남는 내용만 몇 개 다루려고 합니다.

 

1. 객체 구성 시 가장 중요한 것

📖 책 내용

객체지향에서 중요한 개념으로 계속 언급되는 것이 '역할, 책임, 협력'이라는 개념입니다. 객체들이란 각자가 역할을 가지고 객체들 간 협력합니다. 또한 해당 과정에서 객체는 각자가 자신의 역할에 맞게 스스로 행동하고 이에 대한 책임을 각자 집니다. 이런 이유로 위 3 가지 개념을 언급합니다.

💡 내 생각

저는 이런 개념을 간단하게 '분업'이라는 한 가지 개념으로 더 쉽게 이해할 수 있다고 생각했습니다. 당신이 A라는 회사에 재직 중이라고 가정합시다. 당신은 감사팀에 속해 여러 감사 업무를 맡고 있습니다. 이때 A회사의 인사팀에서 새로운 신입사원을 채용한다고 합니다. 당신이 신입사원 채용에 참여할 수 있을까요? 못하겠죠. 인사팀이 담당한 역할 중 하나가 신입사원 채용이고, 감사팀에 속한 당신의 역할은 A 회사에 대한 감사 업무입니다. 감사팀에 속한 당신이 인사팀 업무에 참여한다면 일종의 월권(?)이라고 볼 수 있겠습니다.

위 예시에서 직원 한 명 한 명을 객체라고 가정하니 객체지향에 대해 쉽게 이해할 수 있었습니다. 감사팀에 속한 당신도 객체, 인사팀에 속한 인사팀원도 객체입니다. 이 객체(직원)들은 각자가 가진 역할(업무)이 있습니다. 그리고 서로의 업무를 침해하면 안 되며 각자가 맡은 업무는 본인이 알아서 해결해야 합니다(책임). 또한 객체들은 공통의 목표(회사의 목표)를 위해 도와야 합니다(협력). 결과적으로 객체 지향 프로그래밍을 실현하기 위해서는 회사에서 직원들이 분업하는 상황을 떠올리면 큰 도움이 될 것 같습니다.

 

 

2. 인터페이스와 구현의 분리 원칙

📖 책 내용

객체 외부에서는 객체의 실질적인 구현에 대해서는 정확하게 알지 않아도 돼야 합니다. 객체에 대한 인터페이스만 알아도 쉽게 상호작용할 수 있어야 합니다. 즉, 객체에 대한 수정일 일어나도 인터페이스가 수정되지만 않으면 외부에서 해당 객체를 이용하는데 전혀 문제가 없는 구조가 형성돼야 한다는 의미입니다.

💡 내 생각

이 부분에 대해서는 기존에도 알고 있던 내용이었지만, 인터페이스에 대한 중요성을 일깨워주었습니다. 저는 개인 프로젝트를 진행할 때 인터페이스를 잘 작성하지 않았습니다. 인터페이스를 굳이 작성하지 않아도 사실 프로그램이 실행되는데 전혀 문제 되지 않기 때문이었는데요. 앞으로 더 전문적이고 완성도 있는 개발을 하기 위해서는 인터페이스를 구현하는 데 힘써야 하겠다고 생각했습니다.

 

 


내 코드에 적용해 본 객체지향 프로그래밍

기존에 로그인을 구현했던 코드를 예시로 들겠습니다. 기존 코드 구성은 다음과 같습니다.

하나의 로그인 서비스에 구현된 기능들

위와 같이 하나의 로그인 서비스가 여러 로그인 기능과 회원가입 기능을 구현하도록 설정했습니다. 처음에는 해당 서비스 코드가 로그인 및 회원가입이라는 하나의 역할을 담당한 하나의 객체로 설정되었으니 객체 지향 프로그래밍 관점으로 전혀 문제없다고 생각했습니다. 하지만 너무 많은 역할을 한 객체에 담당시킨 게 아닌가라는 고민이 들기 시작했습니다. 예를 들어 일반 로그인 및 회원가입을 담당하는 객체, 카카오 로그인 및 회원가입을 담당하는 객체, 구글 로그인 및 회원가입을 담당하는 객체로 쪼개면 더 좋지 않을까 싶었습니다. 그 이유는 더 세밀한 역할 분리를 위해서입니다.

예를 들어 애플 로그인 및 회원가입 방식이 추가돼야 한다고 가정합시다. 그러면 위 구조에서는 로그인 서비스 코드에 해당 방식에 대한 코드를 추가하면 됩니다. 이 방식에 큰 문제는 없다고 생각했습니다. 하지만 애초에 애플 로그인 및 회원가입 방식을 담당하는 객체를 따로 두어 객체의 역할을 더 세밀하게 조정할 수 있다면 더 좋지 않을까 하는 생각도 동시에 들었습니다. 아래는 이런 생각을 이용해 수정한 구조입니다.

 

로그인 인터페이스
인터페이스를 통해 세부적으로 구현을 나눈 구조

위 구조에서는 먼저 로그인 인터페이스를 이용해 객체로 구현된 로그인 서비스에는 로그인 및 회원가입이 필요하다는 내용을 정의할 수 있습니다. 즉, 로그인 서비스를 이용하면 로그인을 할 수 있구나! 회원가입도 할 수 있구나!라는 사실을 알 수 있습니다. 하지만 실제로 어떤 과정을 통해 로그인이나 회원가입이 이뤄지는지는 알 필요가 없습니다. 해당 부분은 각 구현체(일반 로그인 서비스, 카카오 로그인 서비스, 구글 로그인 서비스)가 담당해야 하는 것이죠.

만약 로그인 서비스들이 가지고 있는 공통 로직을 구현해야 하거나, 로그인 서비스별로 다른 로직을 구현해야 한다면 인터페이스 대신 추상 클래스를 사용할 수도 있을 것입니다.

추상 클래스를 통해 공통 로직을 구현하고 세부적으로 구현을 나눈 구조

위 예시에서는 추상 클래스를 활용해 토큰 발급이라는 기능은 모든 로그인 서비스들이 가진 공통 로직으로 만들었습니다. 즉, 일반 / 카카오 / 구글 로그인 서비스 모두 같은 기능을 가진 것이죠. 하지만 각 서비스들의 세부적이 로그인 및 회원가입 로직은 다를 수 있고 해당 로직은 알아서 구현하도록 한 구조입니다.

 

❓과연 위 구조가 맞을까..

기존 서비스 코드를 다음과 같이 3개의 서비스 코드로 분리하고 나니 생긴 문제가 있었습니다. 구조의 복잡성인데요. 기본적으로 백엔드 개발을 하시는 분들은 MVC 디자인 패턴을 사용하게 됩니다. 저도 마찬가지인데요. 이때 위와 같은 구조를 만드니 서비스 레이어 코드가 여러 개 생기면서 구조가 명료하게 파악되지 않을 수 있다는 문제점이 생겼습니다. 기존에는 도메인 폴더별로 module 레이어 코드, controller 레이어 코드, service 레이어 코드 하나씩 존재해 구조를 파악하기 굉장히 쉬웠습니다. 하지만 위 경우 service 레이어 코드가 많아지다 보니 구조 파악이 힘들었고, 추후에 기능이 더 많아져서 구현할 것들이 추가되면 이러한 복잡성은 더 가중될 것으로 판단되었습니다.

그래서 이런 객체 지향 프로그래밍을 어디에, 어떻게, 얼마나 적용할 것인지도 굉장히 중요할 것 같다고 생각했습니다. 무작정 모든 코드에 객체 지향 프로그래밍 개념을 적용했다가는 오히려 생산성을 떨어트릴 수 있다고 느꼈끼 때문입니다.

 

+ 2024.11.28 추가 내용

요즘에 객체 지향 관련 자료들을 찾아보다 또 생각이 바뀌어 글을 추가로 작성합니다.

먼저 위 예제에서는 하나의 서비스 코드를 3 가지 서비스 코드로 분리했습니다. 하지만 최근에 든 생각으로는 이것을 효율적인 역할과 책임의 분리로 보기 힘들 것 같다는 것입니다. 오히려 더 복잡해지는 느낌이었습니다.

그래서 이런 역할과 책임의 분리 단위를 도메인으로 설정해야 더 좋을 것 같다고 생각했습니다. 최근 개발을 하면서 auth와 user 두 개의 도메인이 같은 로직을 행한다는 문제를 발견했습니다. auth는 로그인 및 인증 관련 기능만 수행하게 하려고 했습니다. 하지만 회원가입을 하게 되면 해당 유저를 추가하는 로직을 수행해야 했고, 이 부분은 user 도메인에 이미 구현된 내용이었죠.

그래서 auth는 인증 관련 역할과 책임을 다하고, user는 유저 관련 역할과 책임을 다하게 하기 위해 구조를 변경했습니다. auth에서 회원가입 로직 시 회원가입에 성공했을 때 유저를 추가하는 부분은 직접 하지 않고 user 서비스에 요청하는 방식으로 수정한 것입니다. 이로 인해 두 도메인 간 역할과 책임을 온전히 분리할 수 있고 효율적인 개발이 가능하다고 느꼈습니다.

 


마무리

주말 동안 객체 지향 프로그래밍에 대해 복습하면서 내가 그동안 개발했던 코드들은 과연 얼마나 객체를 지향하며 작성되었는지 고민을 많이 하게 되었습니다. 아마 많은 사람들이 공감할 것 같은데요. 앞으로 더 크고 복잡한 개발에 참여하기 위해서는 단순히 기능만 잘 구현된 코드보다는 이런 소프트웨어 공학적 개념들이 잘 녹아든 코드를 작성할 수 있도록 신경 써야 할 것 같다고 느꼈습니다.