Dependency

1hyung·2025년 5월 23일

개발

목록 보기
6/6
post-thumbnail

Dependency(의존성)란?

Dependency는 소프트웨어 개발에서 매우 중요한 개념입니다. 간단히 말해, 어떤 소프트웨어 모듈이나 컴포넌트가 제대로 작동하기 위해 다른 모듈이나 라이브러리에 의존하는 관계를 의미합니다.

Dependency는 프로젝트가 다른 소프트웨어의 기능을 사용하기 위해 필요로 하는 외부 라이브러리나 모듈을 의미합니다. Gradle과 같은 빌드 도구는 이러한 의존성을 효율적으로 선언하고, 자동으로 다운로드하며, 관리하여 개발 과정을 훨씬 더 쉽고 안정적으로 만들어줍니다. build.gradle.kts 파일의 dependencies 블록은 바로 이러한 의존성들을 정의하는 핵심적인 공간이며, 각 의존성 범위(Configuration)는 해당 라이브러리가 언제, 어떻게 사용될지를 Gradle에게 알려줍니다.

Dependency(의존성)란?

  • 정의: 내 프로젝트(모듈, 컴포넌트)가 특정 기능이나 클래스 등을 사용하기 위해 다른 프로젝트나 외부 라이브러리에 필요로 하는 관계를 '의존한다'고 표현하며, 이 필요한 대상을 '의존성(Dependency)'이라고 부릅니다.

  • 예시:

    • A라는 프로그램을 만드는데, 이 A가 로그를 기록하는 기능이 필요하다고 가정
    • 로그 기록 기능을 직접 처음부터 만들 수도 있지만, 이미 Log4j나 Logback 같은 검증된 외부 라이브러리가 존재함
    • 이 라이브러리를 사용하기로 결정했다면, 당신의 A 프로그램은 Log4j 또는 Logback에 '의존'하는 것이고, Log4j나 Logback은 A의 '의존성'이 됨
    • 이때 A가 제대로 작동하려면 Log4j 라이브러리가 반드시 존재해야 함

왜 Dependency를 사용하는가? (Dependency Management의 중요성)

소프트웨어 개발에서 거의 모든 프로젝트는 외부 라이브러리에 의존합니다.

이유

  1. 생산성 향상:
    • 모든 기능을 직접 만들 필요가 없어집니다. 이미 잘 만들어지고 테스트된 라이브러리를 가져다 쓰면 됩니다. (예: 웹 서버, 데이터베이스 연결, JSON 파싱 등)
    • 바퀴를 재발명하지 않음으로써 개발 시간을 단축하고 핵심 비즈니스 로직에 집중할 수 있습니다.
  1. 안정성 및 신뢰성:

    • 수많은 개발자에 의해 사용되고 검증된 오픈소스 라이브러리는 일반적으로 직접 만든 기능보다 버그가 적고 안정성이 높습니다.
    • 보안 취약점이나 성능 이슈가 발견되면 커뮤니티에서 빠르게 패치가 이루어집니다.
  2. 기능 확장:

    • 프로젝트에 필요한 다양한 기능을 손쉽게 추가할 수 있습니다. (예: 이미지 처리, PDF 생성, 암호화 등)
  3. 유지보수 용이성:

    • 각 기능이 모듈화되어 있으므로, 특정 기능에 문제가 발생했을 때 해당 라이브러리를 업데이트하거나 교체하기 용이합니다.
  4. 표준화:

    • 대부분의 프로젝트가 동일한 방식으로 의존성을 관리하므로, 새로운 개발자가 프로젝트에 합류했을 때 이해하기 쉽습니다.

Dependency Management Tools (Gradle, Maven)

이러한 의존성들을 수동으로 관리하는 것은 매우 복잡하고 오류 발생 가능성이 높습니다. (어떤 라이브러리의 어떤 버전이 필요하고, 그 라이브러리는 또 다른 어떤 라이브러리에 의존하는지 등을 일일이 추적하기 어려움)

그래서 Gradle, Maven과 같은 빌드 자동화 및 의존성 관리 도구가 등장했습니다.

주요 역할:

  1. 의존성 선언: 개발자가 build.gradle.kts 파일에 필요한 라이브러리와 버전을 선언하면,
  2. 자동 다운로드: Gradle이 중앙 저장소(Maven Central 등)에서 해당 라이브러리 JAR 파일을 자동으로 다운로드하여 로컬 캐시에 저장합니다.
  3. 전이적 의존성 관리: 선언한 라이브러리가 의존하는 또 다른 라이브러리(전이적 의존성)까지 자동으로 찾아 다운로드하고 관리합니다. (이 기능이 없다면 개발자는 수많은 JAR 파일을 일일이 찾아서 다운로드해야 할 것입니다.)
  4. 버전 충돌 해결: 동일한 라이브러리의 다른 버전이 의존성에 포함될 경우, 합리적인 방식으로 충돌을 해결하려 시도합니다 (예: 최신 버전 사용).
  5. 클래스패스 설정: 빌드 및 런타임 시 필요한 모든 JAR 파일들을 자동으로 프로젝트의 클래스패스에 추가하여 코드가 해당 라이브러리를 사용할 수 있게 합니다.

dependencies 블록의 의미

build.gradle.kts 파일의 dependencies 블록은 "우리 프로젝트가 의존하는 라이브러리 목록"을 선언하는 곳입니다.

dependencies {
    // 여기에 의존성을 추가합니다.
    implementation("org.springframework.boot:spring-boot-starter-web") // 예시
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0") // 예시
}
  • 각 줄은 하나의 의존성을 나타냅니다.

  • implementation, testImplementation, developmentOnly, runtimeOnly 등은 Configuration(설정) 또는 Scope(범위)라고 불립니다. 이들은 의존성이 언제(컴파일 시, 런타임 시, 테스트 시 등) 필요한지, 그리고 다른 모듈로 전이될 때 어떻게 동작할지를 Gradle에게 알려주는 역할을 합니다.

    • implementation(실행):

      • 컴파일 시점과 런타임 시점 모두에 필요합니다.

      • 이 모듈을 사용하는 다른 모듈에게는 이 의존성이 숨겨집니다. 즉, 이 모듈을 라이브러리로 만들었을 때, 라이브러리 사용자가 이 implementation으로 추가된 의존성까지 직접 알 필요가 없습니다. (캡슐화)

      • 가장 일반적으로 사용되는 의존성 범위입니다.

    • api: (주로 라이브러리를 만들 때 사용)

      • implementation과 유사하게 컴파일 시점과 런타임 시점 모두에 필요합니다.

      • implementation과 달리, 이 의존성을 사용하는 다른 모듈에게 이 의존성이 노출됩니다. 즉, 이 모듈을 라이브러리로 만들었을 때, 라이브러리 사용자도 이 api로 추가된 의존성을 직접 사용할 수 있게 됩니다.

      • API를 통해 특정 클래스나 인터페이스를 노출해야 할 때 사용합니다.

    • testImplementation:

      • 오직 테스트 코드 컴파일 및 테스트 실행 시에만 필요합니다.

      • 애플리케이션의 실제 런타임 빌드에는 포함되지 않습니다. (예: JUnit, Mockito)

    • developmentOnly:

      • 오직 개발 환경에서만 필요한 의존성입니다.

      • spring-boot-devtools처럼 프로덕션 빌드에는 포함되면 안 되는 경우에 사용합니다.

    • runtimeOnly:

      • 컴파일 시점에는 필요 없지만, 런타임 시점에 필요한 의존성입니다.

      • 주로 JDBC 드라이버(예: MySQL Connector J)와 같이, 코드가 직접 호출하지는 않지만 애플리케이션 실행에 필요한 서비스 프로바이더 인터페이스(SPI) 구현체에 사용됩니다.

Kotlin 프로젝트에서 사용할 것

Spring Boot DevTools

  • 용도: 개발 생산성을 크게 향상시키는 도구 모음입니다.

  • 주요 기능:

    • 자동 재시작 (Automatic Restart): 코드 변경 사항을 감지하여 애플리케이션을 자동으로 재시작합니다. 개발 과정에서 main 메서드를 다시 실행하거나 빌드 명령을 내릴 필요 없이, 코드를 저장하면 거의 실시간으로 변경 사항이 반영되어 시간을 절약해줍니다.
    • LiveReload: 브라우저에 LiveReload 확장 프로그램을 설치하면, 애플리케이션이 재시작될 때 웹 페이지도 자동으로 새로고침됩니다. (프론트엔드 개발 시 유용)
    • 캐싱 비활성화: 템플릿 엔진 캐싱 등을 기본적으로 비활성화하여, 템플릿 파일 변경 시 즉시 반영되도록 합니다.
    • 글로벌 설정: 여러 프로젝트에서 공통으로 사용할 DevTools 설정을 할 수 있습니다.
  • 왜 사용해야 하나요?

    • 개발 속도를 획기적으로 높여줍니다. 특히 Spring Boot 애플리케이션은 재시작하는 데 시간이 다소 걸릴 수 있는데, DevTools가 이 시간을 단축시켜줍니다.
    • 오류 발생 시 빠르게 피드백을 받을 수 있습니다.
  • build.gradle.kts 추가:


dependencies {
    developmentOnly("org.springframework.boot:spring-boot-devtools")
}
  • developmentOnly 설정: 이 설정은 spring-boot-devtools가 프로덕션 환경으로 배포될 때 빌드에 포함되지 않도록 합니다. 이는 개발 단계에서만 필요한 도구이므로, 실제 서비스 환경에서는 불필요한 리소스를 차지하거나 보안 문제를 야기할 수 있기 때문입니다. 따라서 안심하고 사용하셔도 됩니다.

Spring Web

  • 용도: 웹 애플리케이션(RESTful API, Spring MVC 등)을 개발하기 위한 핵심 디펜던시입니다.

  • 주요 포함 내용:

    • Spring MVC: 웹 요청을 처리하고 응답을 생성하는 데 필요한 프레임워크입니다. @Controller, @RequestMapping, @ResponseBody 등의 어노테이션을 사용하여 API 엔드포인트를 정의할 수 있게 해줍니다.
    • Tomcat (임베디드 서버): 별도의 웹 서버(예: Apache Tomcat, Jetty)를 설치하지 않고도 애플리케이션 자체 내에 웹 서버가 내장되어 있어, JAR 파일 하나로 애플리케이션을 실행할 수 있게 해줍니다.
    • JSON 처리 라이브러리 (Jackson): HTTP 요청/응답 시 객체를 JSON으로 변환하거나 JSON을 객체로 변환하는 기능을 제공합니다.
  • 왜 사용해야 하나요?

    • 웹 서비스 구축의 핵심: 백엔드에서 RESTful API를 제공하거나 웹 페이지를 서빙하려면 spring-boot-starter-web은 사실상 필수입니다. 대부분의 Spring Boot 백엔드 프로젝트는 이 디펜던시를 사용합니다.
    • 편리한 통합: Spring Boot의 "starter" 개념 덕분에, 이 하나의 디펜던시만 추가하면 웹 개발에 필요한 대부분의 라이브러리와 설정이 자동으로 추가되고 구성됩니다.
  • build.gradle.kts 추가:


dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
}
  • implementation 설정: 이 디펜던시는 애플리케이션의 핵심 기능이므로 컴파일 시점과 런타임 시점 모두에 필요합니다.

Kotlin 프로젝트에서 사용하지 말 것

Lombok

Kotlin에서는 Lombok의 필요성이 거의 없으며, Kotlin의 언어 기능을 활용하는 것이 더 자연스럽고 권장되는 방법입니다.

  • 용도: Java에서 반복적인 코드(Getter, Setter, Constructor 등)를 어노테이션으로 대체하여 코드량을 줄여주는 라이브러리입니다.
  • Kotlin에서 사용하지 않는 이유:
    • Kotlin의 data class: Kotlin은 data class라는 언어 차원의 기능을 제공합니다. data class를 선언하면 자동으로 equals(), hashCode(), toString(), copy(), componentN() 등의 메서드를 생성해줍니다. 이는 Java에서 Lombok의 @Data나 @Getter/@Setter 등을 사용했을 때 얻는 이점과 동일하거나 그 이상입니다.
    • Kotlin의 기본값/명명된 인수: 생성자(Constructor)의 인자 기본값 설정이나 명명된 인자 기능 덕분에, Lombok의 @AllArgsConstructor, @NoArgsConstructor 등의 필요성이 많이 줄어듭니다.
    • IDE 지원: IntelliJ IDEA 같은 Kotlin IDE는 Kotlin의 고유한 기능을 잘 지원하며, Lombok이 개입하면 때때로 IDE 기능과 충돌하거나 디버깅에 어려움을 줄 수 있습니다.
    • 언어의 일관성: Kotlin으로 작성된 프로젝트에서 Java 스타일의 Lombok을 사용하는 것은 언어의 일관성을 해치고, 불필요한 의존성을 추가하는 결과를 낳을 수 있습니다.
profile
이유가 많은 사람보다 (자기)개발자가 되고싶은 1hyung입니다.

0개의 댓글