주니어의 시선에서 바라본 빅데이터 클러스터 이사과정 – Pojang24 개발기

소개

안녕하세요 빅데이터플랫폼파트1셀에서 근무하고 있는 koodin입니다. 어느덧 카카오와 함께한 지 2년이 훨씬 지났는데요, 그동안 상용 하둡 플랫폼에서 카카오 하둡 플랫폼(KHP)으로의 전환 프로젝트를 진행하게 되었습니다. 여기에서는 대규모 데이터 이관을 더 쉽고 빠르게 하기 위해 개발하게 된 Pojang24에 대한 소개와 어떤 요구사항이 있었는지, 또 이를 만족하기 위해 어떠한 고민을 했고 어떻게 풀어갔는지에 대해 이야기해보려 합니다.

 

데이터를 옮겨야 합니다

카카오의 많은 부서들이 사용 중인 카카오 공용 하둡에는 수많은 파일과 디렉터리가 있습니다. 그리고 일정 주기마다 오래된 데이터를 콜드 스토리지(Cold storage)로 이관하는 아카이빙 잡(Job)들이 있습니다. KHP 프로젝트를 성공적으로 마무리하기 위해서는, 파일 이관과 더불어, 아카이빙 잡들을 신규 클러스터로 옮기는 작업이 반드시 필요했고, 때마침 신규로 입사하게 된 제가 담당하게 되었습니다. 

 

먼저, 수십 페타바이트 수준의 데이터를 옮겨야 하는 목표를 듣고 어떤 것들을 할 수 있는지 생각했습니다. 수동으로 처리하기에는 너무나 많은 데이터가 존재했기 때문에, 이관을 관리해주는 시스템이 있으면 좋겠다는 생각이 들었습니다. 또한 공용 하둡의 데이터 관리자들이 모두 개발자는 아니기에 하둡을 잘 모르더라도 손쉽게 데이터를 이관할 수 있는 시스템을 만들어야 되겠다는 생각을 했습니다.

 

Oozie 기반의 카카오의 기존 아카이빙 시스템은 하둡 관리자가 잡과 인프라를 관리하는 구조로 되어 있었습니다. 만약 새로운 아카이빙 요청이 들어오면, 관리자는 수동으로 스크립트를 작성하여 새로운 아카이빙 잡이 실행되도록 했죠. 그래서 여러 부서의 테이블 구조를 알고, 작업이 실패했을 경우 확인하는 작업까지도 하둡 관리자가 관리하고 있었습니다. 

 

아파치 우지(Apache Oozie)

하둡의 잡을 관리하기 위한 워크플로 스케줄링 시스템(https://oozie.apache.org/)



이러한 상황에서 기획 중인 사내 시스템은 데이터 이관 외에도 기존 아카이빙 시스템을 개선하자는 목표를 세웠습니다. 이를 위해 첫째, 하둡 관리자가 직접 모든 데이터 아카이빙 작업을 관리하는 게 아닌 사용자가 직접 데이터 플로우를 관리할 수 있도록 하고, 둘째, 기존 아카이빙 시스템을 보완하고 아키텍처의 변경을 통해 하둡 관리자가 아카이빙 작업을 운영하는 비용을 줄이고 싶었습니다.

 

정리하자면 사내 시스템은 아래 주요 목표를 달성하기 위해 기획되었습니다.

  • 데이터 이관을 쉽게 한다.
  • 아카이빙 시스템을 개선한다.

 

그리고, 위 두 가지 요구사항을 만족시키는 시스템을 개발하면서 클러스터 간 데이터 이사를 24시간 쉽게 해주는 시스템이란 뜻으로 “Pojang24(포장이사)”라고 이름을 지었습니다.

 

기존 아카이빙 시스템을 개선합시다

기존 아카이빙 시스템은 여러 가지 불편한 점이 있었습니다. 첫째로 재처리에 대한 자동화가 되어있지 않았죠. 

 

아카이빙이 어떤 문제로 인하여 실패했을 경우 위와 같은 알람 메시지를 받게 되고 관리자는 실패된 건에 대해서 수작업으로 재처리했습니다. 아카이빙 잡이 실패되었을 때 대부분 재시작을 통해서 처리해야 되는 건이 많았고, 매번 수작업으로 재처리를 수행해야 하는 관리자의 피곤함은 아카이빙 데이터에 비례해 늘어만 갔죠. 새로운 아카이빙 시스템은 실패된 작업에 대한 재처리가 자동으로 되어야 했습니다.

 

둘째로 새로운 아카이빙 요청이 생겨났을 때 과거 데이터에 대한 처리가 수동으로 이루어져야 한다는 것이었습니다. 만약 테이블이 오래전에 만들어진 테이블이라면 데이터 생성 시점부터 수작업으로 데이터를 채워 넣어야 했습니다 🥺

 

셋째로 스키마 변경에 대한 처리가 불가했습니다. 분석가에게 서빙되는 데이터는 종종 테이블에 컬럼이 추가된다던가 구조체 필드(struct field)의 내용이 바뀐다던가 변경이 이루어지곤 합니다. 기존 아카이빙 시스템은 이러한 변경사항에 대해 유연하게 대처하지 못하였습니다. 아카이빙 에러 알람이 발생해 이유를 찾아보면 스키마 변경으로 인해 발생한 경우가 많았고 그럴 때마다 관리자는 스키마 변경 작업을 매번 수작업으로 진행하였습니다.

 

마지막으로 아카이빙 현황 모니터링 기능이 빈약하다는 것이었습니다. 수집 대상 데이터, 수집 중인 데이터, 수집 실패 현황, 재처리 여부 현황을 한눈에 파악할 수 있는 모니터링 화면이 필요했습니다. 과거 아카이빙 시스템에서는, 수집 대상 데이터는 Git 리포지토리에서 확인할 수 있었고, 실제 데이터는 Hue에서 따로 확인했어야 했습니다. 그리고 수집 현황은 일일이 개별 작업의 Oozie 코디네이터 클릭해서 확인해야 했는데 Oozie 코디네이터로 등록된 아카이빙 잡들이 많아지면 UI가 느려지는 단점도 있었습니다.

 

이런 요구사항도 있었습니다

하이브(Hive) 테이블 이관

카카오의 많은 데이터는 하이브(Hive) 테이블로 이루어져 있습니다. 자연스럽게 기존 상용 하둡 클러스터에 있던 테이블을 KHP 클러스터로 이관해야 하는 요구사항이 생겼습니다. 하이브 테이블의 이관은 보통 이관하려는 클러스터에서 KHP 클러스터로 통신이 되게끔 하둡 nameservice를 등록하고 hive export / import 구문으로 테이블 및 데이터를 이관하는 방법을 사용할 수 있습니다. 일반적으로 아래와 같은 순서로 작업이 진행됩니다.

  1. Create table 생성에 필요한 메타데이터를 생성하고 이를 Target 클러스터로 이관
  2. 데이터를 클러스터 데이터 복사 툴인 Distcp를 사용하여 Target 클러스터로 이관
  3. Target 클러스터에서 Source 클러스터로부터 전달받은 테이블 생성 메타데이터를 활용하여 테이블 생성
  4. Hive에서 파티션 추가


Pojang24는 이러한 일련의 작업 과정 즉, 워크플로를 정의하고 실행할 수 있어야 했습니다. 

 

카프카로부터 데이터 이관

사내 카프카(Kafka) 서비스의 사용자가 증가하면서 자연스럽게 HDFS Sink로 이관 니즈도 많아졌습니다. 기존에는 이관이 필요한 부서가 직접 컨슈머 개발과 운영을 하여 중복된 리소스가 소비되고 있었습니다. Pojang24에서 통일된 전사 표준 방식의 카프카 토픽에 대한 HDFS 수집을 지원하고자 했습니다. 이를 통해 중복된 개발과 운영으로 인한 리소스 낭비를 줄여보고자 했습니다.

 

어떻게 만들어 갔을까요?

Pojang24는 KHP로 이관을 위해 빠르게 개발해야 했습니다. 따라서 개발언어를 Ruby로 진행하기로 결정했습니다. Ruby의 장점은 무엇보다 팀원들이 가장 익숙한 언어이고 빠르게 개발이 가능하다는 점이었지만 분명한 단점도 존재했습니다. 이는 뒤에서 얘기해보도록 하죠.

 

개발을 시작하기 전 Pojang24에서 사용하는 용어에 대해서 정의하였습니다. 앞서 말한 용어는 DDD(Domain Driven Design)에서 말하는 보편 언어, 유비쿼터스 랭귀지에 해당합니다. 프로젝트에서 사용하는 언어가 통일되지 않으면 매번 번역의 과정이 추가되고 도메인 전문가와 개발자 사이의 오해가 발생할 여지가 늘어납니다. 

 

  • Flow: Pojang24의 기본 작업 단위
    • 사용자가 작업을 생성하면 Unique한 Flow ID가 부여
    • DataMigrationFlow, HiveMigrationFlow 같은 종류가 있음
  • Task: Flow 실행 시 생성되는 개별 인스턴스
    • 예를 들어 아카이빙 작업은 Daily로 Task가 생성
  • Step: Flow를 구성하는 하위 작업 단위, 각 하나의 비즈니스 로직을 수행

 

 

유비쿼터스 랭귀지 정의를 통해 팀원들의 컨센서스 통일, 프로젝트 모델링과 아키텍처에 대한 이해를 높이고, 문제가 발생했을 때 명확한 설명이 가능했습니다.

 

다시 본론으로 돌아와서 Pojang24의 목적은 관리자의 운영 부담을 줄이기 위해 사용자가 직접 데이터 이관과 아카이빙 작업의 관리가 가능하게 하는 것입니다. 이를 위해선 무엇이 필요할까요? 저희 유닛은 설계를 진행하면서 아래와 같은 컴포넌트가 필요하다고 생각했습니다.

 

  • 비즈니스 로직
  • 사용자 요청을 받을 API 서버
  • 워크플로 엔진
    • 사용자가 요청한 작업에 대한 워크플로를 생성하고 아카이빙 잡에 대한 스케줄링이 가능하면서도 과거 아카이빙 시스템의 한계점을 보완할 수 있는 워크플로 엔진 도입
  • 서비스가 배포될 인프라
  • 사용자에게 제공할 UI

 

그러면 첫 번째 목표인 클러스터 간 데이터를 이동하기 위해선 어떤 것들이 필요했는지, 어떻게 구현했는지 얘기해볼까요?

 

데이터 이관을 가능하게 한다

하둡을 잘 모르는 사용자도 손쉽게 데이터 이관을 하기 위해선 어떤 것들이 필요할까요? 먼저 많은 용량을 이관하는 만큼 HDFS Distcp 사용이 반드시 필요했습니다. 따라서 비즈니스 로직이 실행되는 컨테이너는 Distcp와 Hive 쿼리가 가능해야 하며 커버로스(kerberos) 인증이 가능해야 합니다. 또한 사용자들은 내부의 하둡 설정을 신경 쓰지 않아도 되도록 Source / Target 클러스터만 입력해주면 클러스터 간 Distcp가 가능한 환경을 자동으로 구성해주는 Base Docker 이미지를 개발하였습니다. 

 

격리된 실행 콘텍스트 안에서 동작하는 데이터 이관 로직을 담은 프로젝트 pojang24-dag를 개발하였습니다. 데이터 이관 Flow는 대상 데이터를 선정하는 사전 작업, Distcp 실행, 검증(Validation) 작업, 마지막으로 성공 유무에 따라 사용자 알람을 보내는 Step으로 이루어져 있습니다. 프로젝트의 이름에서 눈치채셨겠지만 Pojang24의 Flow들은 Step들이 DAG(Directed Acyclic Graph, 일방향성의 비순환 그래프) 형태로 이루어져 있습니다. DAG로 구성된 데이터 이관 Flow는 이후 워크플로 엔진에 의해 순서대로 Step이 실행됩니다.

 

하이브 테이블 이관을 가능하게 한다

  하이브 테이블 이관은 아래와 같은 순서로 진행됩니다. 

  1. Create table 생성에 필요한 메타데이터를 생성하고 이를 Target 클러스터로 이관
  2. 데이터를 클러스터 데이터 복사 툴인 Distcp를 사용하여 Target 클러스터로 이관
  3. Target 클러스터에서 Source 클러스터로부터 전달받은 테이블 생성 메타데이터를 활용하여 테이블 생성
  4. Hive에서 파티션 추가

 

중복 개발을 피하고자 데이터 이관 Flow를 개발했던 일부 Step을 하이브 테이블 이관 Flow에서 활용합니다. 예를 들면 2번 과정에서 Distcp를 사용해 데이터를 Source에서 Target 클러스터로 이관해야 하는데 이때 데이터 이관 Flow의 Step을 사용합니다.

 

하이브 테이블 아카이빙 Flow에서 지원해야 하는 기능 중 하나는 중간에 테이블 스키마가 변경되었을 때도 파티션 단위로 이관이 가능해야 한다는 것입니다. 하이브 테이블은 파티션 컬럼 단위로 스키마 정의를 다르게 할 수 있습니다. SELECT까지는 문제가 없으나 이관 시 실행하게 되는 “INSERT OVERWRITE TABLE” 구문은 이관 대상이 되는 테이블 컬럼과 SELECT 문으로 읽어온 테이블 / 파티션 컬럼이 같지 않으면 오류가 발생합니다. 이를 해결하기 위해 변경된 스키마를 갖는 파티션을 위한 임시 테이블을 사용합니다. 참고로 아카이빙 테이블은 파케이 포맷(Parquet, 하둡의 컬럼 방식 저장 포맷)으로 GZIP 압축이 되어야 합니다. 과정은 아래와 같습니다.

 

1. 파티션을 담을 임시 파케이 테이블을 생성

2. 원본 테이블로부터 파티션 메타데이터만 생성

3. 아카이빙 테이블에 파티션 메타데이터만 생성

 

4. 임시 파케이 포맷 테이블을 원본과 다른 스키마를 파티션의 스키마로 변경

5. 원본 테이블과 다른 스키마를 가진 파티션을 임시 파케이 테이블로 INSERT OVERWRITE

 

6. 임시 파케이 테이블로부터 아카이빙 테이블로 파티션을 이동

 

하이브 테이블은 이렇게 스키마가 변경될 경우 이관 과정이 복잡하고 제약사항이 많았습니다. 범용적인 사용을 위해 HDFS와 Hive만을 사용하고 있습니다만, 향후에는 Schema Evolution을 제공하는 Apache Iceberg와 같은  Data lake 레이어를 추가하는 것을 고려하고 있습니다.

 

카프카로부터 데이터를 가져오게 한다

개발 인원이 부족했기 때문에 카프카 데이터 수집 기능을 가장 간단하게, 그러나 견고(robust)한 구조로 구성하고자 했습니다. 아파치 플룸(Apache Flume)은 많은 양의 로그 데이터를 쉽게 수집하기 위해 만들어진 오픈소스입니다. Flume은 여러 가지 데이터 수집 Source와 Sink를 지원하고 있었고 별도 개발 없이 간단한 데이터 파이프라인을 구성할 수 있습니다. 사용자가 입력한 토픽(Topic) 정보와 브로커 서버 정보를 읽고 Flume Agent를 실행하는 Step을 개발했습니다. Flume Topology는 간단하게 Kafka Channel, HDFS Sink로만 이루어지게 구성하였습니다.

 

워크플로우 엔진 선정

Pojang24의 주요 목적은 사용자가 직접 데이터 플로우를 관리하는 것입니다. 즉, 수많은 부서들의 Flow를 안정적으로 수용할 수 있으며 스케일아웃(Scale out) 및 페일오버(Failover)를 지원하면 좋겠습니다. 또한 기존 아카이빙 시스템에선 제공하지 못했던 새로운 기능들에 대해 지원이 가능해야 합니다. 예를 들어 신규 아카이빙 건에 대해 과거 데이터에 대한 자동 처리 기능, 특정 Step이 실패했을 때 재처리하는 기능 등 말이죠. 

 

워크플로 엔진으로 거론된 프레임워크는 아래와 같습니다.

 

 

Airflow

Nifi

Jenkins Pipeline

Azkaban

Hive Query / Distcp

Y

Y

Y

Y

스케일 아웃

Y

Y

Y

Y

주요 컴포넌트 페일오버

Y

N

Y

N

실패 작업 재처리

Operator 단위의 재처리가 가능

RetryFlowFile

retry 구문 지원

attempts 설정

과거 데이터 Backfill 지원

Y

N

N

N

히스토리 로그

Remote Logging 지원

nifi-logback.xml 설정 필요

Log rotation 설정

execution.logs.retention.ms로 설정

도커를 통한 실행 컨텍스트 분리

Y

N

Y

N


Nifi는 각 노드들을 관리하는 코디네이터(Coordinator)가 Zero-master 형태로 존재합니다. 

 

제로 마스터(Zero-master)

마스터 노드가 다운되면 전체가 다운되는 SPOF(Single point of failure) 방식이 아니라 다시 마스터를 리더로 선출하는 방식을 말하며, 별도로 마스터의 역할만 하는 노드가 존재하지 않아 제로 마스터라고 합니다.

 

코디네이터 선출을 위해 Zookeeper 서버들의 운영이 필요했습니다. 또한 노드가 문제가 생겨 종료 되었을 때 해당 노드에서 돌고 있던 작업이 해당 노드가 재시작될 때까지 돌지 않습니다. 그러니까 결국 노드를 다시 살릴 때까지 그 노드에서 돌던 작업은 계속 못 돌고 있는 것이죠. 

 

Azkaban은 아직 주요 컴포넌트에 대해서 고가용성(High Availability)이 지원되지 않아 고려 항목에서 제외했죠. Jenkins의 경우 Oozie와 마찬가지로 이력(history)이 쌓일 때마다 UI에서 로드하는 시간이 오래 걸려 사용성이 좋지 않았습니다.

 

결과적으로 Airflow를 사용하기로 결정했습니다. Airflow는 쿠버네티스 오퍼레이터(Kubernetes Operator)를 지원하여 이를 사내 컨테이너 서비스를 연동시킨다면 인프라 운영에 대한 부담을 덜 수 있었습니다. 

 

쿠버네티스 오퍼레이터(Kubernetes Operator)

커스텀 컨트롤러라고도 합니다. 오퍼레이터는 사용자 정의 커스텀 리소스를 해석해서 쿠버네티스 상의 자원으로 배포하는 역할을 합니다.

 

또한 컨테이너 서비스에 노드를 추가하기만 하면 자동으로 스케일아웃(Scale-out)이 지원되었고 웹서버(Web server), 스케줄러(Scheduler)에 대한 고가용성(High Availability) 지원이 가능했습니다. 게다가 기존 아카이빙 시스템에서 지원하지 못했던 실패한 Task에 대한 자동 재시작 기능, 그리고 logical_date에 따른 캐치업(Catchup) 실행(정해진 시간에 실행되지 못한 DAG를 지연 실행하는 것)을 통해 새로운 아카이빙 요청에 대한 과거 데이터 처리가 가능했습니다. Daily로 실행한 아카이빙 잡에 대한 풍부한 모니터링 기능과 실행한 단계의 로그도 저장할 수 있어, 스케줄러를 Airflow을 기반으로 개발하게 되었습니다. 

 

아카이빙 작업 모니터링

UI는 무엇보다 작업 상태를 한눈에 알아볼 수 있는 가시성이 중요했습니다. 수집 대상 데이터는 무엇인지 실행 중인 작업 상태와 실패된 작업의 구분, 재처리 여부 현황을 쉽고 빠르게 확인할 수 있도록 개발하였습니다. 

 

아카이빙 페이지는 원본 데이터를 가진 Source 클러스터와 Target 클러스터를 보여주면서 데이터의 보관 기간을 보여줍니다. Target 유지 만기일은 Optional이며, 설정이 된 경우 입력한 날짜만큼 Target 클러스터에 보관되고 이후 영구적으로 삭제됩니다.

 

아카이빙 작업 상태는 한눈에 알아보기 쉽게 색으로 구분합니다. 초록색은 작업이 정상적으로 수행됐음을 의미합니다. 하늘색은 작업이 진행 중임을 의미합니다. 마지막으로 빨간색은 작업이 실패했고 Flow의 Owner가 직접 원인을 확인해야 하는 경우입니다.

 

 

또 각 작업의 상태는 스케줄링에 의해 처리된 것과 수작업으로 실행시킨 작업으로 나뉘는데요, 이 둘은 테두리 선으로 구분하였고 실패된 작업에 마우스를 호버 하게 되면 어떤 날짜를 대상으로 아카이빙 처리를 하다 실패했는지 나오게 됩니다.

 

데이터 캐치업(Catchup)

이전 아카이빙 시스템은 새로운 테이블을 아카이빙 시킬 때 과거 데이터에 대한 처리가 자동화되지 않았습니다. 그래서 관리자는 아카이빙을 시작할 테이블의 데이터 시작 일자를 확인하고 수작업으로 과거 데이터를 채워 넣어야 했습니다. 새로운 아카이빙 시스템은 이러한 문제를 해결하기 위해 데이터 캐치업(Catchup)을 지원합니다. 

 

예를 들어 Source Cluster에서 데이터를 365일 동안 보관하고 이후 데이터는 콜드 스토리지(Cold Storage)로 이관을 하는 상황입니다. 데이터가 2014-04-06 부터 존재한다면 위와 같이 “Catchup Start Date”를  2015-04-06으로 설정하면 데이터가 존재하는 날짜로부터 아카이빙 작업이 수행됩니다. 위 기능으로 관리자가 수동으로 하나씩 데이터를 채워주지 않아도 사용자가 직접 손쉽게 새로운 아카이빙 테이블을 추가할 수 있게 되었습니다.

 

실패 / 성공 알람

데이터 플로우의 관리 주체를 사용자로 넘기면서 관리자가 받던 실패 작업 알람을 사용자들도 받아볼 수 있는 알람 기능을 추가하였습니다.

 

아카이빙 작업은 실시간 분석과 같이 민감한 SLA(Service Level Agreement)를 가지지 않기 때문에 카카오톡과 같이 피로도가 큰 형태의 알람 형태가 아닌 게시글 형태로 알람을 구현하였습니다.  알람을 통하여 사용자는 이관 작업이나 아카이빙 작업의 상태를 확인하고 업무시간에 실패 작업에 대한 재시도를 수행하게 됩니다.

 

 

수백 테라바이트 크기의 데이터를 옮기는 경우 Flow 작업은 오랜 시간이 걸립니다. Flow 성공 알림을 받고 싶은 사용자들은 Flow 생성 시점에 카카오 워크 웹 훅 URL을 입력하게 하여, 이관 완료 시점을 빠르게 알 수 있게 하였습니다.

 

이건 좀 아쉽더라구요

Pojang24를 운영하면서 새로운 기능을 추가하거나 성능 개선 등과 같은 작업을 진행하면서 후회되었던 몇 가지 사례에 대해 말씀드리겠습니다.

 

하이브 커넥터(Hive Connector) 좀 제대로 만들걸

Pojang24는 하이브 파티션(Hive Partiton)을 이관해주는 기능을 구현해야 하는 만큼 Hive 서버에 접속하여 쿼리가 가능해야 했습니다. 프로젝트를 시작하면서 빠른 개발을 위하여 조직 공용 언어인 Ruby를 사용했었고 이후 Hive 쿼리를 실행하기 위한 모듈을 개발했어야 했습니다. “rbhive”라는 프레임워크를 도입하고자 했으나 지원하는 Hive 버전이 매우 낮았고 쿼리도 일부분만 지원되어 사용할 수 없었습니다. 

 

당시 클러스터를 운영하면서 Beeline을 사용해 Hive 쿼리를 날리는 경우가 대부분이었고 클러스터 간 Distcp가 가능한 환경의 Base 이미지를 만들었기 때문에 자연스럽게 Ruby에서 Beeline 세션을 열어 사용하게 되었습니다. 그러나 이러한 접속 방식은 매번 쿼리를 날려줄 때마다 새로운 커넥션을 만들기 때문에 작업에 오랜 시간이 걸리게 되었습니다. 

 

결국 제대로 된 Hive Connector를 만들고 커넥션 관리를 해주었다면 더욱 좋은 성능으로 쿼리할 수 있었을 텐데 후회가 남네요. 이런 식의 대안이 있을 거라 생각됩니다. 첫째로 Ruby로 된 JDBC Connector는 없으니 JRuby를 사용하고 Java에서 사용하는 Hive Connector를 사용하는 방법, 둘째로 hive 통신 부분을 따로 나눠서 별도의 서비스로 제공하고 Pojang24 API 서버에서는 REST 요청을 통해 쿼리를 하는 것 등이죠.

 

지나친 상속

Pojang24의 일부 코드에는 상속을 사용하였습니다. 상속은 잘 사용하면 편리하지만 그만큼 잘 사용하지 않으면 유지 보수하기 힘든 거대한 코드가 만들어지게 됩니다. Pojang24에서 데이터 이관이란 행위는 거의 모든 Flow에서 행해집니다. 따라서 코드의 중복을 막기 위해 상속을 사용하였습니다. 즉, 상속을 코드 재사용을 위한 용도로 활용하였고 부모 클래스와 자식 클래스 사이의 강한 밀결합(Coupling)이 형성되었습니다. 이후 기능을 추가하거나 기존 코드를 수정할 경우 상속을 사용한 모든 부분에 영향을 미치게 되었습니다. 여기서 고친 코드로 인해 다른 곳에 있는 유닛 / 통합 테스트가 실패하는 등의 문제가 발생하게 되었죠. 

 

기능이 추가되면서 점점 커지는 클래스들이 서로 어떤 의존 관계를 가지고 있는지 파악하기 힘든 지경에 이르렀고 막바지에는 그 누구도 그 코드를 건드리고 싶지 않은 공포 그 자체가 돼버렸습니다.

 

사실 데이터 이관의 역할을 가지는 클래스와 이를 중간 단계에서 사용하는 클래스의 관계는 “IS-A” 관계가 아닌 “HAS-A” 관계였으니 클래스를 상속하지 않고 컴포지션 방식으로 하나의 Private 필드로 참조하는 방식을 사용했으면 좀 더 유연하고 확장성 높은 코드를 만들지 않았을까 아쉬움이 남았습니다.

 

결론

다사다난했던 KHP 이전 프로젝트가 어느덧 막바지에 이르렀습니다. Pojang24는 3명의 개발자가 반년여의 개발 기간을 거쳐 탄생하였습니다. Pojang24를 통하여 약 4000여 개 Flow를 생성했고 40 페타바이트 수준의 데이터를 이관하였습니다. KHP 전환에 Pojang24가 분명 도움이 되었을 거라 생각하니 그동안 했던 고민과 고생이 헛되이 되진 않았구나 하는 안도감과 함께 많은 것들이 생각났습니다. 주니어인 제가 카카오라는 환경에서 좋은 팀원들과 일하면서 느낀 것들은 아래와 같습니다.

 

  • 유지보수 편한 코드를 만드는 것이 생각보다 정말 중요하구나
  • 책에서 말하는 안티 패턴들은 전부 경험을 통해 나온 것이구나
  • 좋은 코드는 좋은 리뷰에서 나오는구나
  • 사용자 서비스를 기획/개발할 수 있는 역량과 자신감을 얻었다!

 

이 글을 읽고 아카이빙 시스템 개발을 고려하고 있는 개발자나 처음으로 주도적인 프로젝트를 시작하려는 주니어분들에게 도움이 되었길 바라며 글을 마치겠습니다.



카카오톡 공유 보내기 버튼

Latest Posts

대학생 멘토링: 우물 밖 내다보기

https://www.youtube.com/watch?v=LGdb4Q5t-gw 안녕하세요. 저는 카카오톡 톡플랫폼개발팀에서 백엔드 서버 개발자로 일하고 있는 nano.son(손은호)입니다. 2023년 1월 16일, 제 모교인 경북대학교의 학생들과 판교 아지트에서 멘토링을 진행했습니다.