의존성에 대해서

profile image 스이연 2025. 3. 20. 22:35

최근에 공부하고 있는 주제가 의존성이다.

스프링을 다루면서 자주 언급되는 개념 중 하나인데, 의존성에 대해서 공부하게 되면 시스템 설계를 할 때 생각해 볼 것들이 많을 것 같아 눈여겨 보는 중이다!

 

의존이란?

의존은 다른 객체나 함수를 사용하기만 해도 의존이라고 한다.

이때 어떤 객체나 코드를 사용하기만해도 결합이라는 것이 생긴다고도 한다.

우리는 의존성이나 결합도를 낮출수록 좋은 코드라고 할 수 있다.

 

의존성을 낮추려면?

의존성 주입이라는 기법을 사용한다.

의존성 주입이란 필요한 의존성을 외부에서 넣어주는 것을 의미한다.

 

의존성이 높은 코드

class HambugerChef {
	public Food make() {
		Bread bread = new WhatBread();
		Meat meat = new Beef();
		Vegetable vegetable = new Lettuce();
		Sauce sauce = new TomatoSauce();
		
		return Hamberger.builder()
				.bread(bread);
				.meat(meat)
				.vegetable(vegetable)
				.sauce(sauce)
				.build();
	}
}

 

의존성이 약한 코드 (생성자 주입 기법)

class HambugerChef {

	public HamburgerChef(Bread bread, Meat meat, Vegetable vegetable, Sauce sauce){
		this.bread = bread;
		this.meat = meat;
		this.vegetable = vegetable;
		this.sauce = sauce;
	}
	
	public Food make() {
		return Hamberger.builder()
				.bread(bread);
				.meat(meat)
				.vegetable(vegetable)
				.sauce(sauce)
				.build();
	}
}

 

의존성이 높은 코드의 경우 WhatBread, Beef, Lettuce, TomatoSauce 와 같은 구체적인 클래스에 의존하고 있다.

하지만 의존성이 약한 코드의 경우 위의 구체 클래스에 의존하지 않기 때문에 의존성이 10개에서 6개로 줄어든다.

의존성을 아예 없애는 것이 아닌 의존성 주입으로 불필요한 강한 의존이 생기지 않게 해서 의존성을 약하게 하는 것이 중요하다.

new 사용을 자제하라는 격언이 있듯이, new 사용을 할 경우 특정 구체 클래스에 의존을 하게 되어 더 이상 다른 객체가 사용할 여지가 사라지게 된다.

위에서 작성한 의존성이 강한 코드 처럼 meat에 new Beef를 사용해서 고기를 소고기로 고정시키게 된다면 햄버거는 소고기만 사용하게 되어 가능성이 하나로 고정된다는 문제점이 있다.

따라서 상세한 구현 객체에 의존하는 것을 피하고 구현 객체가 인스턴스화 되는 시점을 최대한 뒤로 미루는 것이 중요하다.

 

의존성 역전

의존성 역전의존성 주입

의존성 역전 = Dependency Inversion

의존성 주입 = Dependency Injection

 

Restaurant → HamburgerChef
: Restaurant 클래스가 HamburgerChef 클래스에 의존한다.

Restaurant → Chef(interface) ← HamburgerChef
: Restaurant 클래스와 HamburgerChef는 Chef 인터페이스에 의존한다.
  즉 추상화를 이용한 간접 의존 형태로 바꿨다. = 의존성을 역전 시켰다.

 

HamburgerChef 의 화살표 방향이 들어오는 방향에서 나가는 방향으로 바뀌었다.

Restaurant → HamburgerChef 에서는 HamburgerChef에 무언가(Restaurant)가 의존 하도록 만들었다면 의존성 역전을 시켰을 때는 HamburgerChef가 무언가(Chef)에 의존 되도록 하는 것이다.

 

인터페이스를 하나의 정책이라고 부른다면 구현하는 객체는 세부사항이라고 부를 수 있다.

따라서 의존성 역전 원칙은 세부 사항에 의존하지 않고 정책에 의존하도록 코드를 작성하는 것이다.

 

의존성 역전을 하게 되면 경계를 만들게 되는데, 이때 경계는 모듈의 범위를 정하고 상하 관계를 만드는 것이다.

Restaurant → Chef(interface) ← HamburgerChef

위의 경우 restaurant 모듈과 hamburger 모듈로 나눈다고 했을 때 restaurant 모듈에는 Restaurant 클래스와 Chef 인터페이스가 포함될 것이고 hamburger 모듈에는 HamburgerChef 클래스가 포함될 것이다.

 

여기서 상하를 나누면 restaurant 모듈이 상위 모듈이고 hamburger 모듈이 하위 모듈이다.

하위 모듈은 상위 모듈에 의존하지만 상위 모듈은 하위 모듈에 의존하지 않는다.

이렇게 상하위 모듈을 나누게 된다면 추후 hamburger 모듈을 다른 하위 모듈로 바꾸었을 때 restaurant 모듈에 영향을 받지 않고 자유롭게 기능을 변경할 수 있다.

 

의존성이 왜 중요한가요?

코드를 추후 변경할 일이 생길 때 변경으로 인한 영향 범위가 적을 수록 좋은 코드라고 할 수 있다.

그래서 의존성을 잘 관리할 수록 변경으로 인한 영향 범위가 줄어들게 된다.

 

의존성이 높을 수록 한 컴포넌트가 변경되거나 영향을 받으면 그 컴포넌트와 관련된 다른 컴포넌트도 영향을 받게 된다. 이를 의존성 전이라고 한다.

 

의존성 전이는 순환 참조 문제와도 연관이 있는데, 순환 참조란 두개의 컴포넌트가 서로 참조를 하게 되는 것을 말한다. 만약 순환 참조가 일어나고 있는 컴포넌트중 하나에 변경이나 영향이 있을 경우 연결된 참조 컴포넌트도 영향이 갈 뿐만 아니라 이와 또 연결된 다른 컴포넌트에도 영향이 가기 때문에 문제가 발생한다.

따라서 순환 참조를 만들지 않으려면 양방향 참조를 끊어내고 단방향으로 만들어야한다.

 

 

느낀 점
의존성을 잘 관리 하는 것이 추후 유지보수나 변경이 이루어졌을 때 영향이 가는 컴포넌트들도 적어지기 때문에 관리가 수월해질 수 있겠다는 생각이 들었다.
단순히 구현을 위주로 생각하는 것이 아닌 설계할 때 추상화 구조를 더 신경써야겠다는 점을 배웠다.

 

출처
자바/스프링 개발자를 위한 실용주의 프로그래밍 서적

'Programming > Java' 카테고리의 다른 글

Interface와 Abstract  (1) 2025.06.15
JVM이 무엇이고 구조에 대해 알아보자  (0) 2025.05.10
원시타입과 참조 타입  (2) 2025.05.04
BufferedReader와 BufferedWriter  (2) 2025.02.15
객체지향에게 역할과 책임이란  (1) 2025.02.11