프로그래밍에서 스파게티 코드 — 개념, 원인 및 회피 방법

저자: IT Sectr 게시일: 2026-07-26 읽는 시간: 10 분

스파게티 코드(스파게티 코드, 국수 코드)— 논리 블록이 순서 없이 뒤얽힌 혼란스럽고 무질서한 프로그램 구조입니다. TIOBE Index(2024) 연구에 따르면, 스파게티 코드 수준이 높은 프로젝트는 새 기능을 구현하는 데 2.5배 더 많은 시간이 필요합니다. 이 용어는 goto 문이 프로그램의 임의 지점 간 이동을 허용하여 읽을 수 없는 구조를 만들던 초기 프로그래밍 시대에 등장했습니다.

핵심 요점

  • 스파게티 코드 — 명확한 구조가 없는 코드로, 다른 모듈의 로직이 무작위로 뒤얽힘
  • 주요 원인: 아키텍처 부재, goto, 전역 변수 및 계층 혼합
  • 비용 스파게티 코드 유지보수는 잘 구조화된 코드보다 3–4배 높음
  • 리팩토링 국수 코드는 함수 추출, 계층 분리 및 의존성 주입 구현 포함
  • 패턴 MVC, MVVM 및 Clean Architecture가 주요 예방 도구

스파게티 코드란

스파게티 코드 — 코드 구조가 스파게티 접시와 유사함을 설명하는 은유입니다. 개별 가닥(논리 블록)이 뒤엉키고 붙어 서로 분리할 수 없습니다. 이러한 코드에서는 계층, 모듈 또는 구성 요소를 분리하는 것이 불가능합니다 — 모든 것이 하나의 큰 덩어리로 혼합됩니다.

단순히 부주의할 수 있는 나쁜 코드와 달리, 스파게티 코드는 근본적인 아키텍처 문제입니다. 좋은 변수 이름으로 완벽하게 포맷된 코드라도 아키텍처가 혼란스러우면 스파게티 코드가 될 수 있습니다. 문제는 작성 스타일이 아닌 프로그램 구조 수준에 있습니다.

IEEE(2022)에 따르면, 대규모 프로젝트의 모든 오류 중 약 35%가 개발자의 논리 오류가 아닌 코드 구조의 뒤얽힘으로 인해 발생합니다. 개발자가 작업을 잘못 이해해서가 아니라 스파게티 코드에서 실행 흐름을 추적할 수 없었기 때문에 실수를 범합니다.

다른 안티패턴과의 주요 차이점

나쁜 코드가 단일 함수나 파일 규모의 나쁜 코드라면, 스파게티 코드는 전체 애플리케이션 규모의 나쁜 아키텍처입니다. 국수는 개별적으로 잘 작성된 함수로 구성될 수 있지만, 그 상호 작용은 혼란스럽고 예측 불가능합니다.

용어의 역사와 goto 시대

“스파게티 코드”라는 용어는 1970년대 goto 문에 대한 비판과 함께 등장했습니다. 초기 프로그래밍 언어(BASIC, FORTRAN, COBOL)에서 goto는 실행 흐름을 제어하는 주요 방법이었습니다. 프로그램은 번호가 매겨진 줄의 시퀀스였고, goto는 그 중任何 하나로 점프할 수 있게 했습니다. 이는 풀 수 없는 점프의 “얽힘”을 만들었습니다.

1968년, 에츠허르 데이크스트라는 그의 유명한 편지 “Go To Statement Considered Harmful”을 발표하여 구조적 프로그래밍 시대의 시작을 알렸습니다. 데이크스트라는 모든 알고리즘이 goto 없이 순차, 분기(if), 루프(while)의 세 가지 구조만으로 구현될 수 있음을 증명했습니다. 이것이 현대 프로그래밍의 기초가 되었습니다.

구조적 프로그래밍은 문제를 완전히 제거하지 못했습니다. 스파게티 코드는 새로운 수준으로 이동했습니다 — 물리적 goto 대신 개발자는 논리적 “goto”를 만들기 시작했습니다: 전역 변수, JavaScript의 콜백 지옥, 복잡한 호출 체인 및 구성 요소 간의 암시적 의존성입니다. 문제는 남았고 형태만 바뀌었습니다.

goto의 현대적 형태

콜백 지옥, 깊이 중첩된 Promise, 오류 처리 없는 async/await, 누가 언제 트리거하는지 아무도 이해하지 못하는 이벤트 — 이 모든 것이 스파게티 코드의 현대적 변종입니다. 안티패턴은 살아있고 번성하고 있으며, 단지 지금은 goto 문을 사용하지 않을 뿐입니다.

프로젝트에서 스파게티 코드의 징후

계층 부재 — 첫 번째이자 주요 징후입니다. 스파게티 코드에서는 비즈니스 로직, 데이터베이스 작업, HTML 마크업 및 네트워크 통신이 모두 하나의 파일 또는 하나의 메서드에 혼합됩니다. 데이터베이스 쿼리를 변경하면 UI 표시가 깨질 수 있습니다. 이러한 계층의 코드가 분리되지 않았기 때문입니다.

전역 변수 및 싱글톤 — 두 번째 명백한 징후입니다. 애플리케이션 상태가 전역 객체에 저장되면 실행 흐름을 예측할 수 없게 됩니다. 모든 함수가 전역 상태를 변경할 수 있으며, 이것이 어디서 언제 발생했는지 추적하는 것은 사실상 불가능합니다.

갓 클래스 및 갓 함수 — 세 번째 징후입니다. 비즈니스 로직, 표시 및 데이터 작업을 처리하는 2000줄 이상의 클래스 — 이것이 전형적인 스파게티 코드입니다. 10개의 매개변수를 받아 5가지 다른 작업을 수행하는 함수 — 역시 스파게티입니다.

징후설명예시
계층 혼합UI 코드 내 SQL 쿼리직접 DB 쓰기를 하는 컨트롤러
전역 변수어디서나 접근 가능한 상태모든 클래스의 static SessionManager
갓 클래스하나의 클래스가 모든 것을 함3000줄의 OrderManager
긴 메서드분해 없는 함수5개의 책임을 가진 200줄 메서드
콜백 지옥끝없이 중첩된 콜백JavaScript에서 6단계 중첩

테스트를 통한 진단

만약 15개의 모의 객체를 만들지 않고 함수에 대한 단위 테스트를 작성할 수 없다면 — 그것은 스파게티 코드입니다. 단일 모듈을 테스트하는 데 전체 애플리케이션 인프라를 가동해야 한다면 — 그것은 스파게티 코드입니다. 테스트 불가능성은 뒤얽힌 아키텍처의 객관적인 지표입니다.

국수 코드가 발생하는 이유

아키텍처 설계 부재 — 가장 흔한 원인입니다. 팀이 계획 없이 코드 작성을 시작하고 아키텍처를 “즉흥적으로” 선택하면 결과는 필연적으로 스파게티가 됩니다. 각 새 기능은 논리적으로 속한 곳이 아닌 “지금 편리한” 곳에 추가됩니다.

진화적 개발 — 두 번째 원인입니다. 프로젝트는 작은 스크립트로 시작하여 기능이 추가되고 애플리케이션이 되었다가 모놀리스가 됩니다. 그동안 아키텍처는 재고되지 않습니다. 100줄의 코드에서 작동하던 것이 100,000줄에서는 재앙이 됩니다.

SOLID 원칙 위반 — 세 번째 원인입니다. 특히 단일 책임 원칙(S)과 의존성 역전 원칙(D)입니다. 클래스가 모든 것에 책임이 있고, 의존성이 경직되며 모듈이 강하게 결합되면 — 스파게티 코드가 됩니다.

시간 요소

마감 및 핫픽스 문화 — 스파게티 코드의 촉매제입니다. “어제 필요했다”면 개발자는 아키텍처를 고려하지 않고 첫 번째 사용 가능한 위치에 코드를 삽입합니다. 이러한 핫픽스가 10개 있으면 — 애플리케이션 아키텍처가 파괴됩니다.

스파게티 코드의 결과

주요 결과 — 코드베이스에 대한 통제력 상실입니다. 개발자는 애플리케이션이 전체적으로 어떻게 작동하는지 이해하지 못하게 됩니다. 한 곳의 변경이 다른 겉보기에 관련 없는 곳을 깨뜨립니다. 각 패치는 두 개의 새 버그를 만듭니다. 팀은 “변경에 대한 두려움” 상태에 빠집니다.

생산성은 기하급수적으로 떨어집니다. Microsoft Research(2023)는 스파게티 코드에서 새 기능을 추가하는 시간이 코드베이스 크기에 대해 제곱으로 증가함을 보여주었습니다. 클린 아키텍처의 경우 이 증가는 선형입니다. 차이는 50,000줄 이상의 코드에서 중요해집니다.

보안 — 또 다른 희생자입니다. 스파게티 코드에서는 처리되지 않은 예외, 잘못된 입력 검증 또는 데이터 유출을 놓치기 쉽습니다. 뒤얽힌 아키텍처 프로젝트의 보안 감사는 사실상 불가능합니다 — 사용자 입력이 사용되는 모든 위치를 찾는 것이 비현실적입니다.

팀에 미치는 영향

이직률은 스파게티 코드가 있는 프로젝트에서 평균 이상입니다. 경험 많은 개발자는 “국수”로 작업하기를 원하지 않아 떠납니다. 새 직원은 코드를 이해할 수 없어 첫 몇 달 안에 떠납니다. 프로젝트는 전문성을 잃어 코드 품질을 더욱 악화시킵니다 — 악순환입니다.

스파게티 코드 리팩토링 방법

첫째 — 계층 분리부터 시작하십시오. 코드를 세 가지 수준으로 나누십시오: 프레젠테이션(UI, 컨트롤러), 비즈니스 로직(서비스, 사용 사례), 데이터 액세스(리포지토리, DAO). 부분적인 분리만으로도 즉시 구조가 개선되고 코드를 테스트 가능하게 만듭니다.

둘째 — 의존성 주입을 구현하십시오. 생성자나 매개변수를 통해 의존성을 전달하여 직접 의존성 생성을 대체하십시오. 이는 구성 요소 간의 경직된 연결을 끊고 각 모듈을 격리하여 테스트할 수 있게 합니다.

셋째 — 갓 클래스와 갓 함수를 추출하십시오. 단일 책임을 가진 작은 클래스와 메서드로 분할하십시오. 복잡한 하위 시스템을 단순화하기 위해 Facade 패턴을 사용하십시오. 기억하십시오: 20줄의 클래스가 2000줄의 클래스보다 명확합니다.

javascript
// 스파게티 — 모든 것이 하나의 메서드에
function handleRequest(req, res) {
  const db = new Database("mysql://...");
  const user = db.query("SELECT * FROM users WHERE id =" + req.params.id);
  let html = "";
  html += "

" + user.name + "

"
; html += "

Balance: " + user.balance + "

"
; html += ""; res.send(html); } // 클린 아키텍처 — 분리된 계층 class UserController { constructor(userService) { this.userService = userService; } async getUser(req, res) { const user = await this.userService.findById(req.params.id); res.json(new UserResponse(user)); } } class UserService { constructor(userRepository) { this.userRepository = userRepository; } async findById(id) { return await this.userRepository.findById(id); } }

리팩토링 전략: 수술적 방법

한 번에 전체 코드베이스를 다시 작성하려고 하지 마십시오 — 그것은 확실한 실패입니다. 하나의 모듈을 선택하고, 현재 동작을 캡처하는 특성 테스트를 작성한 후에만 리팩토링하십시오. 점진적으로, 모듈별로 스파게티를 풀어나갈 것입니다.

국수 코드 예방

아키텍처 계획 — 예방의 기초입니다. 개발을 시작하기 전에 아키텍처 스타일을 승인하십시오: MVC, MVVM, Clean Architecture, VIPER 등. 선택을 정당화하는 ADR(Architecture Decision Record)을 작성하십시오. 코드 리뷰에서 아키텍처 준수를 요구하십시오.

의존성 역전 원칙(DIP) — 스파게티 코드에 대한 강력한 도구입니다. 고수준 모듈은 저수준 모듈에 의존해서는 안 됩니다. 둘 다 추상화에 의존해야 합니다. 의존성 주입은 이 원칙의 실용적인 구현입니다.

테스트 — 최고의 예방책입니다. 코드보다 먼저 테스트를 작성하면(TDD) 필연적으로 느슨하게 결합된 구성 요소를 설계합니다. 테스트 가능한 코드는 잘 구조화된 코드입니다. 테스트 불가능한 코드는 거의 항상 스파게티 코드입니다.

  • 아키텍처를 코드보다 먼저: 계층 및 의존성 스키마 승인
  • 의존성 주입을 주요 바인딩 패턴으로
  • TDD 또는 최소한 높은 테스트 커버리지
  • 코드 리뷰에서 스타일뿐만 아니라 아키텍처도 확인
  • 정기적인 리팩토링을 개발 프로세스의 일부로

스파게티 코드 퇴치 도구

SonarQube — 순환 복잡도, 상속 깊이, 메서드 크기를 추적합니다. JDepend(Java) — 패키지 간 의존성을 측정합니다. PhpMetrics — PHP 프로젝트의 유지 관리 가능성 지수를 제공합니다. CI/CD에서 메트릭을 모니터링하십시오 — 사후 대처가 아닌 국수 발생을 예방하십시오.

자주 묻는 질문

스파게티 코드를 완전히 다시 작성하지 않고 수정할 수 있나요?

, 점진적 리팩토링이 더 바람직합니다. Strangler Fig 방법을 사용하십시오 — 애플리케이션을 중단하지 않고 이전 구성 요소를 새 구성 요소로 점차 교체하십시오. 데이터 계층 또는 비즈니스 로직을 분리하는 것부터 시작하십시오. 기능 손실을 방지하기 위해 변경 전에 이전 코드를 테스트로覆盖하십시오.

스파게티 코드와 라자냐 코드의 차이점은 무엇인가요?

스파게티 코드 — 모든 애플리케이션 계층이 혼란스럽게 뒤얽힌 것입니다. 라자냐 코드는 엄격한 다계층 아키텍처이지만, 각 계층이 너무 분리되어 있어 데이터 전송이 관료적이 됩니다. 두 안티패턴 모두 해롭지만, 스파게티 코드가 더 위험합니다 — 코드를 예측 불가능하게 만들기 때문입니다.

코드 리뷰에서 스파게티 코드를 식별하는 방법은?

의존성을 살펴보십시오: 모듈이 애플리케이션의 모든 계층에서 모듈을 임포트한다면 — 의심스럽습니다. 메서드 크기에 주의하십시오 — 30줄을 초과하면 일반적으로 나쁩니다. 함수가 UI 작업, 비즈니스 로직 및 데이터를 혼합하는지 확인하십시오. 그렇다면 — 그것은 스파게티 코드입니다.

어떤 아키텍처가 스파게티 코드를 가장 잘 방지하나요?

Robert Martin의 Clean ArchitectureHexagonal Architecture(Ports & Adapters) — 두 가지 최고의 접근 방식입니다. 둘 다 계층 분리, 프레임워크로부터의 비즈니스 로직 독립성 및 테스트 가능성을 보장합니다. 모바일 개발의 경우 — Repository 패턴과 함께 MVVM.

스파게티 코드를 자동으로 감지할 수 있나요?

부분적으로. 순환 복잡도(McCabe), 모듈 결합도, 상속 트리 깊이(DIT)와 같은 메트릭이 잠재적 스파게티 코드를 나타냅니다. SonarQube, CodeClimate 및 PhpMetrics는 이러한 메트릭을 자동으로 계산합니다. 그러나 완전한 진단에는 인간의 아키텍처 분석이 필요합니다.

요약

  • 스파게티 코드 — 논리 블록이 서로 분리 불가능한 혼란스러운 구조의 안티패턴
  • 용어는 1970년대 goto 문의 과도한 사용으로 인해 생겨남
  • 주요 징후: 계층 혼합, 전역 변수, 갓 클래스
  • 스파게티 코드 프로젝트에서 팀 생산성이 기하급수적으로 하락
  • 리팩토링은 계층 분리와 의존성 주입 구현부터 시작
  • Clean Architecture와 TDD가 스파게티 코드 최고의 예방책
  • 복잡도와 결합도 메트릭이 코드에서 국수를 자동 감지하는 데 도움

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기