Monorepo 란?

좐쓰 ㅣ 2025. 4. 25. 17:31

반응형

Monorepo는 "모노 레포지토리"의 줄임말로, 여러 프로젝트를 하나의 코드 저장소에서 관리하는 방식이다. 각 프로젝트가 독립적으로 운영될 수 있지만, 공통의 라이브러리나 코드, 도구를 공유할 수 있어 효율성을 높인다.

장점

  1. 버전 관리의 일관성: 모든 코드가 하나의 저장소에 있기 때문에 의존성 버전 관리를 통일화하기 쉽다.
  2. 코드 재사용: 공통 모듈이나 라이브러리를 여러 프로젝트에서 쉽게 사용할 수 있다.
  3. 쉬운 협업: 팀원들이 동일한 저장소에서 작업하므로 코드 변경 사항과 업데이트를 실시간으로 확인하고 협업하기 용이하다.
  4. 단일 빌드 및 배포: 전체 시스템을 포함한 단일 빌드와 배포가 가능하여 코드 변경 시 통합 테스트가 용이하다.

단점

  1. 대규모 코드베이스 관리: 코드베이스가 커질수록 성능 문제가 발생할 수 있으며, CI/CD 시스템의 부하가 증가할 수 있다.
  2. 시간 소모적인 의존성 관리: 프로젝트 간에 의존성 문제가 발생할 경우, 이를 해결하는 데 시간이 소요될 수 있다.
  3. 개발 환경 설정의 복잡성: 다양한 프로젝트가 동일한 환경에서 실행되기 때문에 환경 설정이 복잡해질 수 있다.

 

프로젝트 구조

/my-monorepo
│
├── /shared
│   └── src/main/java/com/example/shared/Utils.java
│   └── build.gradle
│
├── /project-a
│   └── src/main/java/com/example/projecta/ProjectAApplication.java
│   └── build.gradle
│
└── /project-b
    └── src/main/java/com/example/projectb/ProjectBApplication.java
    └── build.gradle

 

 

1. shared/build.gradle: 공통 모듈 설정

plugins {
    id 'java'
}

group = 'com.example'
version = '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    // 필요시 공통 라이브러리 의존성 추가
}

 

2. shared/src/main/java/com/example/shared/Utils.java

package com.example.shared;

public class Utils {
    public static String greet(String name) {
        return "Hello, " + name + "!";
    }
}

 

3. project-a/build.gradle: 프로젝트 A 설정

plugins {
    id 'org.springframework.boot' version '2.7.0'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.example'
version = '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    implementation project(':shared')  // 공유 모듈 의존성
    implementation 'org.springframework.boot:spring-boot-starter'
}

// Spring Boot의 메인 클래스를 지정
bootJar {
    mainClassName = 'com.example.projecta.ProjectAApplication'
}

 

4. project-a/src/main/java/com/example/projecta/ProjectAApplication.java

package com.example.projecta;

import com.example.shared.Utils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProjectAApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProjectAApplication.class, args);
        String message = Utils.greet("Alice");
        System.out.println(message);  // 출력: Hello, Alice!
    }
}

 

5. project-b/build.gradle: 프로젝트 B 설정

plugins {
    id 'org.springframework.boot' version '2.7.0'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.example'
version = '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    implementation project(':shared')  // 공유 모듈 의존성
    implementation 'org.springframework.boot:spring-boot-starter'
}

// Spring Boot의 메인 클래스를 지정
bootJar {
    mainClassName = 'com.example.projectb.ProjectBApplication'
}

 

 

6. project-b/src/main/java/com/example/projectb/ProjectBApplication.java

package com.example.projectb;

import com.example.shared.Utils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProjectBApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProjectBApplication.class, args);
        String message = Utils.greet("Bob");
        System.out.println(message);  // 출력: Hello, Bob!
    }
}

 

Root build.gradle: 루트 Gradle 설정

rootProject.name = 'my-monorepo'
include 'shared'
include 'project-a'
include 'project-b'

 

루트 settings.gradle 파일은 Gradle이 관리할 서브프로젝트를 정의한다. 각각의 서브프로젝트를 명시하여 Gradle이 의존성을 관리할 수 있도록 돕는다. 여기서는 shared, project-a, project-b 세 가지 서브프로젝트가 포함되어 있다.

 

각각의 서브프로젝트에 대해 독립적인 build.gradle 파일을 설정하여, 각 프로젝트의 의존성을 정의하고 Spring Boot 관련 플러그인을 적용하였다.

  • 공통 모듈 (shared): 공통의 유틸리티 함수와 의존성을 정의하고, 다른 애플리케이션에서 사용할 수 있도록 했다.
  • 각 애플리케이션 (project-a, project-b): Spring Boot 애플리케이션으로 설정하고, 자신의 메인을 통해 애플리케이션 로직을 구현하도록 했다. 각 애플리케이션에서는 shared 모듈을 참조하고, 필요한 라이브러리를 추가하여 독립적으로 작업할 수 있다.

 

 

추가 고려사항

  • CI/CD 설정: Monorepo는 CI/CD 파이프라인에서 통합과 배포를 보다 쉽게 할 수 있지만, 빌드 시간이 길어질 수 있다. 변경된 파일만 빌드하는 등을 통해 성능을 최적화할 수 있는 전략이 필요하다.
  • 관계 관리: 서브 프로젝트 간의 의존성을 명확히 하고, 각 모듈의 레퍼런스를 잘 관리하는 것이 중요하다. Gradle의 기능을 활용해 의존성을 효과적으로 관리할 수 있다.
  • 패키지화: 필요에 따라 각 프로젝트를 독립적인 패키지로 배포할 수 있다. Maven 중앙 저장소에 배포하거나 사내 저장소에 배포하는 방안도 고려할 수 있어, 각 서비스가 독립적으로 운영될 수 있다.

이러한 방식을 통해 Monorepo 구조의 이점을 최대한 활용하며 애플리케이션을 효과적으로 개발하고 관리할 수 있다.

반응형