의존성
A dependency exists when a change in one software component may require a change in another component.
— 소프트웨어 공학 권위 서적에서 밝히는, 하나의 부품이 변동되었을 때 이를 물고 있는 다른 이웃 부품들에게 파괴적인 연쇄 정밀 영향력을 전파하는 종속적 성향 정의
혼자서는 아무것도 구동할 수 없는 의존투성이 나약한 객체들이 서로의 손목을 치렁치렁 케이블로 묶고 달리는 기괴한 디지털 인간 띠. 사실상 남이 짜놓은 라이브러리를 쉽고 편하게 가져다 쓰기 위한 문명의 축복이자, 역설적으로 남의 코드 버그 취약점 한 번에 내 서비스까지 도미노처럼 폭사당하는 운명 공동체(...)
1. 개요
한 소프트웨어 클래스나 모듈, 혹은 전체 프로젝트 시스템이 자신의 미션 목적을 정상 완수하기 위해 반드시 외부의 다른 객체나 제3자 패키지 부품의 도움에 철저히 지배당하고 결합해야 하는 종속적 상태를 뜻한다. 소프트웨어 아키텍처 및 객체지향의 근원적인 화두이다.
2. 단단한 결합(Tight)과 느슨한 결합(Loose)
아키텍처 설계 공학에서 의존성은 결합도의 세기에 따라 '가장 유해한 악마'와 '아름다운 천사'로 양분된다.
- 단단한 결합(Tight Coupling): 클래스 A가 구체적인 특정 클래스 B의 클래스명을 내부에 박아 직접 인스턴스를 무지성 생성(
new B())하는 비극적 상태이다. B 클래스의 생성자 파라미터가 단 하나라도 바뀌는 순간 A 소스코드까지 줄줄이 빨간불 컴파일 오류가 동반 폭사한다. 부품 간 격리가 안 되어 유지 보수가 사정없이 불가능하다. - 느슨한 결합(Loose Coupling): 직접 구체 객체를 가리키는 대신, 가볍고 유연한 인터페이스(Interface)를 앞장세워 의존 관계를 가볍게 맺는 똑똑한 방식이다. 실제 구현체가 뒤바뀌어도 내 메인 비즈니스 논리는 한 줄도 정정할 필요가 없어 유연성의 극치를 달린다.1
3. 우아한 구원: 의존성 주입 (Dependency Injection, DI)
이 느슨한 결합의 기적을 완벽 구현하는 아키텍처 비법이 바로 모던 백엔드 스프링(spring-boot)의 기둥이자 전산학의 찬란한 유산인 의존성 주입(Dependency Injection, DI) 기술이다. 객체 내부에서 스스로 필요한 부품을 생성(new)해 갖추는 주도권을 완전히 박살 낸다. 대신, 외부의 거대한 부품 공장 컨테이너(DI Container)가 부팅 시점에 개입하여, '자, 너희들은 인터페이스 규격 구멍만 뚫고 얌전히 대기해라, 필요한 알맹이 부품은 내가 뒤에서 구멍에 쑥 꽂아 넣어줄게' 하고 동적으로 부품을 주입해 조립해 준다. 이 제어 역전 마법 덕분에 개발자들은 코드를 다 뜯어고칠 필요 없이 테스트용 Mock 부품과 실제 운영용 DB 부품을 클릭 한 번으로 가볍게 바꿔치기하며 수리하고 호사스럽게 코딩할 수 있게 되었다.
4. 관련 밈 및 드립
4.1. NPM Left-pad 대소동 기습 밈
2016년 한 개발자가 깃허브에 올린 문자열 왼쪽 패딩 11줄짜리 사소한 라이브러리를 삭제하자, 전 세계 수만 개의 리액트, 바벨 빌드 시스템들이 이 11줄짜리 부품에 의존(Dependency)하여 물밑 체인 연결되어 있다가 도미노처럼 우르르 폭사 사망한 전설적 해프닝이다. 전산실에서는 '우리는 잘난 척 온갖 복잡한 코딩 설계를 다 하지만, 결국은 이름도 모르는 인도인 개발자의 11줄짜리 소스 하나에 내 수억짜리 비즈니스 목숨줄이 의존당해 지배받고 있는 것과 같다'며 자조적인 넋두리를 남기곤 한다.(...)
5. 여담
- 의존성 지옥 (Dependency Hell): 라이브러리를 너무 신나게 설치하다 마주치는 절망적 버그 꼬임이다. 패키지 A를 깔려면 B 1.0 버전이 필요한데, 패키지 C를 깔려면 B 2.0 버전이 요구되어, 컴파일러가 '나는 대체 B를 어느 장단에 맞춰 로딩해야 하느냐'며 자폭을 터트린다. 이를 수리하기 위해 패키지 락 파일(package-manager)을 열고 한 땀 한 땀 버전 수동 정렬 노가다를 처단해야 한다.
- 순환 참조 (Circular Dependency) 저주: 클래스 A는 B가 없으면 동작을 못 하는데, B는 또 작동하기 위해 A를 요구하는 환장할 상호 의존 꼬임 상태이다. 이들을 그냥 가동하면 메모리 내부의 부팅 엔진이 뱅글뱅글 무한 재귀 참조 루프에 빠져 스택오버플로우 시뻘건 비명 에러를 뿜어내며 부팅 자체를 영구 폭사거부 당한다.
- 의존성 락(Lock)의 안전핀: 개발자들이 다 같이 협업할 때, 누군가 라이브러리 새 버전을 무심코 업데이트했다가 내 컴퓨터에서 소스가 깨져 작동 안 하는 참사를 막기 위해 패키지 매니저들은
package-lock.json,pnpm-lock.yaml등의 '의존성 락 파일'을 자동으로 굽는다. 이 파일은 모든 종속 라이브러리의 엄격한 빌드 해시값과 버전을 잠가두어 전 세계 엔지니어들이 단 1비트의 꼬임 없이 똑같은 환경으로 빌드하게 방어해 준다.
6. 관련 문서
각주
-
실제로 이 의존성 결합도를 낮추는 객체지향 5대 개발 표준 가이드를 컴퓨터 공학에서는 'SOLID' 법칙이라 부르며, 그중 마지막 'D'가 바로 인터페이스 역전을 통한 구체화 회피를 뜻하는 '의존성 역전 원칙(Dependency Inversion Principle)'의 정수이다. ↩