이 연구의 핵심 아이디어는 **"내 집 (코드) 이 아주 깨끗하고 완벽해도, 내 이웃 (의존하는 다른 코드) 이 문제가 있으면 내 집도 자주 수리를 받아야 한다"**는 것입니다.
1. 문제의식: 왜 내 집은 깨끗한데 자주 고쳐야 할까?
소프트웨어 개발자들은 보통 "내 코드에 버그나 나쁜 설계 (코드 스멜) 가 있으면 자주 고쳐야 한다"고 생각합니다. 하지만 이 연구는 **"내 코드는 깨끗한데, 내가 의존하는 다른 코드가 나쁘면 내 코드도 자주 흔들린다"**는 사실을 발견했습니다.
비유: 당신이 아주 깔끔하고 완벽한 집을 지었다고 칩시다. 그런데 당신의 이웃이 매일 밤 시끄러운 파티를 열거나, 집이 무너져 내릴 듯 위태롭다면? 당신은 그 소음이나 붕괴 위험 때문에 당신의 집도 자주 수리하거나 방어를 해야 하지 않겠습니까?
연구의 질문: "내 집 (클래스) 이 깨끗해도, **내 이웃 (Efferent Neighbor)**이 나쁜 상태라면 내 집이 얼마나 자주, 얼마나 많이 고쳐져야 하는가?"
2. 핵심 개념: "코드 스멜"과 "연쇄 반응"
코드 스멜 (Code Smell): 코드가 냄새나는 상태입니다. 예를 들어, 한 사람이 모든 일을 다 하려고 하거나 (신경질적인 클래스), 너무 복잡하게 얽혀 있는 경우죠.
이웃 (Efferent Neighbor): 내 코드가 "의존"하는 다른 코드들입니다. 내 코드가 작동하려면 그 이웃들의 도움이 필요하다는 뜻입니다.
연쇄 반응 (Ripple Effect): 이웃이 수정되면, 그 영향이 내게까지 퍼져나가는 현상입니다.
3. 이 연구가 발견한 두 가지 중요한 현상
이 논문은 단순히 "이웃이 나쁘다"는 것을 넘어, 두 가지 더 구체적인 상황을 분석했습니다.
① 서로 냄새가 섞인 경우 (Interrelation)
상황: 내 집에도 나쁜 냄새가 있고, 이웃 집에도 나쁜 냄새가 있는 경우입니다.
비유: 내가 술에 취해 있고, 이웃도 술에 취해 있다면, 둘이 부딪히면 상황이 훨씬 더 엉망이 되겠죠?
결과: 두 곳 모두 문제가 있으면, 그 영향이 겹쳐서 내 집이 훨씬 더 자주, 더 크게 고쳐져야 합니다.
② 직접적인 연결 고리 (Interaction)
상황: 내 코드의 나쁜 부분과 이웃 코드의 나쁜 부분이 직접적으로 연결되어 있는 경우입니다.
비유: 내 집의 수도관 (나쁜 설계) 이 이웃 집의 수도관 (나쁜 설계) 과 직접 연결되어 있다면, 이웃이 수도관을 고칠 때 내 수도관도 함께 고쳐야 할 확률이 훨씬 높아집니다.
결과: 단순히 이웃이 나쁜 것보다, 나쁜 부분끼리 직접 손잡고 있는 경우가 시스템의 안정성을 가장 크게 해칩니다.
4. 연구 방법: 어떻게 확인했나요?
연구진들은 GitHub 에 있는 인기 있는 Java 프로젝트 100 개를 선정했습니다.
관측 기간: 1 년 동안의 수정 기록 (커밋) 을 분석했습니다.
측정: "내 집이 얼마나 자주 수정되었는지 (빈도)"와 "한 번 수정할 때 얼마나 많은 코드가 바뀌었는지 (크기)"를 잰 뒤, 그 이웃들의 상태 (냄새 유무, 연결 상태) 와 비교했습니다.
통계: 수학적인 모델을 사용하여 "이웃이 나쁘면 실제로 내 집이 더 불안정해지는가?"를 증명했습니다.
5. 결론: 우리에게 어떤 교훈이 있나요?
이 연구는 소프트웨어 개발자들에게 다음과 같은 중요한 메시지를 줍니다.
나만 깨끗하면 된다는 생각은 위험합니다. 내 코드만 잘 짜도, 의존하는 외부 라이브러리나 다른 모듈이 나쁘면 내 코드도 자주 고쳐야 합니다.
이웃을 관리하세요. 프로젝트의 안정성을 높이려면, 내가 의존하는 '이웃' 코드들의 상태도 함께 점검하고 리팩토링 (정리) 해야 합니다.
직접 연결된 나쁜 코드는 가장 위험합니다. 나쁜 코드끼리 직접 연결되어 있다면, 그 영향력이 배가되므로 가장 먼저 해결해야 할 우선순위입니다.
📝 한 줄 요약
"내 집이 아무리 깨끗해도, 나쁜 이웃과 직접 연결되어 있으면 내 집도 자주 고쳐야 한다. 그래서 소프트웨어를 만들 때는 '나'뿐만 아니라 '내 이웃'의 상태도 함께 챙겨야 한다."
이 연구는 소프트웨어 유지보수 비용을 줄이고, 더 안정적인 시스템을 만들기 위해 우리가 시야를 넓혀야 함을 보여줍니다.
1. 연구 배경 및 문제 제기 (Problem)
소프트웨어 유지보수의 핵심: 소프트웨어 유지보수 (버그 수정, 리팩토링, 기능 추가) 는 소스 코드 변경을 수반하며, 변경이 작고 국소적일수록 비용이 적고 부작용 위험이 줄어듭니다. 반대로, 빈번하거나 대규모로 변경되는 클래스는 **불안정 (Instability)**하다고 간주됩니다.
기존 연구의 한계: 기존 연구들은 주로 변경 대상 클래스 자체에 존재하는 코드 냄새 (Code Smells) 가 유지보수성을 해친다고 가정하고, 해당 클래스의 불안정성을 분석했습니다.
새로운 문제 인식:
외향적 이웃 (Efferent Neighbors) 의 영향: 클래스 C가 의존하는 다른 클래스들 (외향적 이웃) 이 변경될 경우, 정적 의존성 (Static Dependencies) 을 따라 파급 효과 (Ripple Effects) 가 발생하여 C도 변경을 강요받을 수 있습니다. 이때 이웃 클래스에 코드 냄새가 존재하면 이 파급 효과가 더 빈번하고 심각해질 수 있습니다.
코드 냄새의 상호관계 (Interrelation) 와 상호작용 (Interaction): 코드 냄새는 단독으로 나타나지 않고, 같은 클래스 내나 의존 관계에 있는 클래스들 사이에 함께 나타납니다. 특히 정적 의존성을 통해 직접 연결된 두 개의 코드 냄새 인스턴스 간의 **상호작용 (Interaction)**은 모듈성, 이해 가능성, 수정 용이성을 더욱 악화시킬 수 있으나, 이에 대한 실증적 연구는 부족합니다.
연구 목적: 클래스 자체의 냄새뿐만 아니라, 외향적 이웃에 존재하는 코드 냄새와 이웃 간의 냄새 상호작용이 해당 클래스의 안정성에 어떤 영향을 미치는지 실증적으로 규명하는 것입니다.
2. 연구 방법론 (Methodology)
이 연구는 100 개의 인기 있는 GitHub 오픈소스 Java 프로젝트에 대한 대규모 실증 연구 (Empirical Study) 입니다.
2.1 데이터 수집 및 시스템 선정
대상: GitHub 의 'Top-Starred' 프로젝트 중 다음 기준을 만족하는 100 개 Java 프로젝트 선정.
100 개 이상의 포크, 20 명 이상의 기여자, 최소 1 년간 50 회 이상의 커밋, 코드 80% 이상이 Java, 교육용 프로젝트 제외.
관측 기간: 각 프로젝트의 스냅샷 (Snapshot) 을 기준으로 그 이후 1 년간의 커밋 히스토리를 분석합니다.
2.2 변수 정의
독립 변수 (Independent Variables, IVs):
클래스 자체 냄새: 냄새 유무, 냄새 개수, 냄새 종류 다양성.
외향적 이웃 냄새: 이웃 클래스에 냄새가 있는지, 냄새 개수, 종류 다양성.
외향적 코드 냄새 커플링 (Efferent Code Smell Coupling): 대상 클래스와 이웃 클래스 모두에 냄새가 존재하는 경우.
외향적 코드 냄새 상호작용 (Efferent Code Smell Interaction): 대상 클래스의 냄새 인스턴스와 이웃 클래스의 냄새 인스턴스가 정적 의존성 (호출 등) 으로 직접 연결된 경우. 상호작용의 강도 (Intensity) 를 측정합니다.
종속 변수 (Dependent Variables, DVs): 클래스 안정성 지표
변경 빈도 (Change Frequency): 기간 내 클래스가 수정된 커밋 횟수.
변경 크기 (Change Size): 기간 내 추가/삭제된 코드 라인 수 (코드 churn).
통제 변수 (Control Variables): 클래스 크기 (Lines of Code), 외향적 이웃 수 (Efferent Coupling).
2.3 도구 및 분석 기법
코드 냄새 탐지:JSpIRIT 도구 사용 (Lanza & Marinescu 의 정의에 기반한 10 가지 냄새: God Class, Brain Class, Feature Envy 등).
의존성 분석:CodeQL을 사용하여 정적 의존성 (Call, Create, Use 등 10 가지 관계) 추출.
리팩토링 식별:RefactoringMiner를 사용하여 클래스 리네임, 이동, 분할, 병합 등을 식별하고 분석에서 제외하거나 처리.
통계 모델:
Negative Binomial Generalized Linear Models (GLMs): 카운트 데이터 (변경 횟수, 라인 수) 의 과분산 (Overdispersion) 특성을 반영하기 위해 사용.
Project-level Random Intercepts: 프로젝트 간 차이 (개발 문화, 팀 규모 등) 를 통제하기 위해 무작위 효과 모델 사용.
가설 검정: Benjamini-Hochberg (BH) 절차를 사용하여 다중 비교 보정 후, 단측 검정 (One-sided test) 수행.
3. 주요 연구 질문 및 가설 (Key Research Questions)
RQ1: 클래스 자체의 코드 냄새 존재가 안정성에 영향을 미치는가? (기존 연구 재검증)
RQ2:외향적 이웃의 코드 냄새 존재가 해당 클래스의 안정성에 영향을 미치는가? (핵심 기여점)
특히, 클래스 자체는 깨끗하지만 이웃이 냄새가 있는 경우에도 안정성이 떨어지는지 확인.
RQ3:외향적 코드 냄새 커플링 (대상 클래스와 이웃 모두 냄새 존재) 이 안정성에 영향을 미치는가?
RQ4:외향적 코드 냄새 상호작용 (두 냄새가 정적 의존성으로 직접 연결됨) 이 안정성에 영향을 미치는가?
4. 기대 결과 및 기여 (Expected Results & Contributions)
실증적 증거: 기존 연구가 간과했던 "의존성 기반의 파급 효과"를 통해, 깨끗한 클래스라도 의존하는 이웃이 냄새가 있으면 불안정해질 수 있음을 입증할 것으로 예상됩니다.
상호작용의 영향: 단순히 냄새가 여러 개 있는 것을 넘어, 냄새들이 정적 의존성으로 **직접 연결된 경우 (Interaction)**가 유지보수성을 더욱 심각하게 저해한다는 것을 규명할 것입니다.
공공 데이터: 모든 소스 코드, 분석 스크립트, 데이터를 공개하여 연구의 재현성 (Replicability) 을 보장합니다.
실무적 시사점:
코드 냄새 탐지 및 리팩토링 우선순위 설정 시, 단순히 클래스 내부만 보는 것이 아니라 **의존 관계 (Dependency Graph)**를 고려해야 함을 시사합니다.
특히 외향적 의존성이 많은 클래스나, 냄새가 상호작용하는 구조를 가진 모듈을 우선적으로 리팩토링해야 함을 제안합니다.
5. 연구의 의의 및 한계 (Significance & Limitations)
의의: 소프트웨어 유지보수 분야에서 '코드 냄새'와 '안정성'의 관계를 **내재적 요인 (클래스 자체)**뿐만 아니라 **외재적 요인 (의존 관계)**을 포함하여 종합적으로 분석한 최초의 엄밀한 연구 중 하나입니다. 이는 정적 의존성이 유지보수 비용에 미치는 영향을 정량화합니다.
한계 및 위협 (Threats to Validity):
내적 타당성: 스냅샷 시점의 냄새와 1 년 후의 안정성 측정 사이의 시간적 불일치 (Time-varying changes).
구축 타당성: 도구 기반의 냄새 탐지가 개발자의 주관적 판단과 다를 수 있음. 모든 의존성 유형을 동일하게 가중치 처리함.
외적 타당성: Java 프로젝트와 인기 있는 오픈소스 프로젝트에 국한되어 다른 언어나 소규모 프로젝트에 일반화하기 어려울 수 있음.
요약
이 논문은 **"클래스의 불안정성은 단순히 그 클래스 자체의 문제뿐만 아니라, 그 클래스가 의존하는 다른 클래스 (외향적 이웃) 의 상태, 그리고 이들 간의 냄새 상호작용에 의해 결정된다"**는 가설을 검증합니다. 이를 통해 소프트웨어 유지보수 전략을 단순한 코드 스캔을 넘어 시스템 아키텍처와 의존성 구조를 고려한 리팩토링으로 확장할 수 있는 이론적, 실증적 기반을 마련합니다.