Java 프로젝트 구조 관리 방법

JavaBeginner
지금 연습하기

소개

효과적인 프로젝트 구조는 성공적인 Java 개발에 매우 중요합니다. 이 포괄적인 가이드는 Java 프로젝트를 구성하는 기본 원리를 탐구하여, 개발자에게 확장 가능하고, 유지 관리 가능하며, 잘 구조화된 소프트웨어 솔루션을 만드는 데 대한 실질적인 통찰력을 제공합니다.

기본 Java 프로젝트 구조 생성

Java 프로젝트는 개발자가 코드를 효과적으로 관리하는 데 도움이 되는 특정 조직 규칙을 따릅니다. 이 단계에서는 기본 구성 요소를 이해하기 위해 간단한 Java 프로젝트 구조를 수동으로 생성합니다.

Java 프로젝트 구성 요소 이해

Java 프로젝트는 일반적으로 다음을 포함합니다.

  • 소스 코드 파일 (.java)
  • 컴파일된 바이트코드 파일 (.class)
  • 리소스 파일 (구성, 이미지 등)
  • 문서

간단한 프로젝트 구조 생성

작업 공간에서 기본 프로젝트 구조를 생성하는 것으로 시작해 보겠습니다. 개념을 설명하기 위해 간단한 "HelloWorld" 애플리케이션을 빌드합니다.

  1. 먼저, LabEx 환경에서 터미널을 엽니다. 터미널은 이미 /home/labex/project 디렉토리에 있어야 합니다.

  2. Java 애플리케이션을 위한 프로젝트 디렉토리를 생성합니다.

mkdir -p hello-java-app/src
cd hello-java-app
  1. src 디렉토리 내에 간단한 Java 클래스 파일을 생성합니다.
mkdir -p src/com/example/app
  1. 이제 첫 번째 Java 클래스를 생성해 보겠습니다. 코드 편집기를 열고 hello-java-app/src/com/example/app/ 경로에 HelloWorld.java라는 새 파일을 생성합니다.
package com.example.app;

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, Java Project World!");
    }
}
  1. 이 Java 코드를 컴파일해 보겠습니다. 터미널에서 프로젝트 루트로 다시 이동하여 다음을 실행합니다.
cd /home/labex/project/hello-java-app
mkdir -p bin
javac -d bin src/com/example/app/HelloWorld.java

컴파일이 성공하면 출력에 오류가 표시되지 않아야 합니다.

  1. 이제 컴파일된 Java 애플리케이션을 실행합니다.
java -cp bin com.example.app.HelloWorld

다음 출력을 볼 수 있습니다.

Hello, Java Project World!

프로젝트 구조 이해

생성한 내용을 검토해 보겠습니다.

hello-java-app/
├── bin/              ## 컴파일된 바이트코드 (.class 파일)
│   └── com/
│       └── example/
│           └── app/
│               └── HelloWorld.class
└── src/              ## 소스 코드 (.java 파일)
    └── com/
        └── example/
            └── app/
                └── HelloWorld.java

이 구조는 다음 원칙을 따릅니다.

  • 소스 코드 분리: 모든 Java 소스 파일은 src 디렉토리에 있습니다.
  • 패키지 구조: com.example.app 패키지는 com/example/app/ 디렉토리에 해당합니다.
  • 컴파일된 코드 분리: 바이트코드 파일은 별도의 bin 디렉토리에 있습니다.

핵심 개념

  • 패키지 (Packages): Java 는 클래스를 구성하고 이름 충돌을 방지하기 위해 패키지를 사용합니다.
  • 디렉토리 구조 (Directory structure): 패키지 이름은 디렉토리 구조에 직접 매핑됩니다.
  • 클래스패스 (Classpath): -cp 플래그는 Java 에 컴파일된 클래스를 찾을 위치를 알려줍니다.

이제 기본 Java 프로젝트 구조를 수동으로 생성했습니다. 이 기반은 실제 애플리케이션에서 사용되는 더 복잡한 프로젝트 구조를 이해하는 데 도움이 됩니다.

패키지를 사용하여 Java 코드 구성

이 단계에서는 패키지를 사용하여 Java 코드를 구성하고 여러 클래스를 사용하여 더 구조화된 애플리케이션을 만드는 방법을 배웁니다. 유지 관리 가능한 Java 프로젝트를 위해서는 적절한 패키지 구성이 필수적입니다.

패키지 규칙 이해

Java 패키지는 계층적 명명 규칙을 따릅니다.

  • 도메인 이름으로 시작 (예: com.example)
  • 프로젝트 또는 조직 이름 추가 (예: com.example.project)
  • 기능 영역 추가 (예: com.example.project.model)

프로젝트에서 이 구조를 구현해 보겠습니다.

다중 패키지 프로젝트 생성

다양한 관심사를 위한 별도의 패키지를 사용하여 간단한 도서관 관리 시스템을 구축합니다.

  1. 프로젝트 디렉토리로 이동합니다.
cd /home/labex/project
mkdir -p library-app/src
cd library-app
  1. 구조화된 패키지 레이아웃을 생성합니다.
mkdir -p src/com/example/library/model
mkdir -p src/com/example/library/service
mkdir -p src/com/example/library/util
  1. 먼저, 모델 클래스를 생성합니다. 코드 편집기를 열고 library-app/src/com/example/library/model/ 경로에 Book.java라는 새 파일을 생성합니다.
package com.example.library.model;

public class Book {
    private String title;
    private String author;
    private int year;

    public Book(String title, String author, int year) {
        this.title = title;
        this.author = author;
        this.year = year;
    }

    // Getters
    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public int getYear() {
        return year;
    }

    @Override
    public String toString() {
        return "Book{title='" + title + "', author='" + author + "', year=" + year + "}";
    }
}
  1. 다음으로, library-app/src/com/example/library/service/BookService.java에 서비스 클래스를 생성합니다.
package com.example.library.service;

import com.example.library.model.Book;
import java.util.ArrayList;
import java.util.List;

public class BookService {
    private List<Book> books = new ArrayList<>();

    public void addBook(Book book) {
        books.add(book);
    }

    public List<Book> getAllBooks() {
        return new ArrayList<>(books);
    }

    public Book findBookByTitle(String title) {
        for (Book book : books) {
            if (book.getTitle().equalsIgnoreCase(title)) {
                return book;
            }
        }
        return null;
    }
}
  1. library-app/src/com/example/library/util/BookFormatter.java에 유틸리티 클래스를 생성합니다.
package com.example.library.util;

import com.example.library.model.Book;

public class BookFormatter {
    public static String formatBookInfo(Book book) {
        return String.format("'%s' by %s (%d)",
            book.getTitle(), book.getAuthor(), book.getYear());
    }
}
  1. 마지막으로, library-app/src/com/example/library/LibraryApp.java에 메인 애플리케이션 클래스를 생성합니다.
package com.example.library;

import com.example.library.model.Book;
import com.example.library.service.BookService;
import com.example.library.util.BookFormatter;

public class LibraryApp {
    public static void main(String[] args) {
        // Create service
        BookService bookService = new BookService();

        // Add some books
        bookService.addBook(new Book("The Great Gatsby", "F. Scott Fitzgerald", 1925));
        bookService.addBook(new Book("To Kill a Mockingbird", "Harper Lee", 1960));
        bookService.addBook(new Book("1984", "George Orwell", 1949));

        // Display all books
        System.out.println("Library Catalog:");
        for (Book book : bookService.getAllBooks()) {
            System.out.println(BookFormatter.formatBookInfo(book));
        }

        // Find a specific book
        Book foundBook = bookService.findBookByTitle("1984");
        if (foundBook != null) {
            System.out.println("\nFound book: " + foundBook);
        }
    }
}
  1. 모든 Java 파일을 컴파일합니다.
mkdir -p bin
javac -d bin src/com/example/library/model/Book.java src/com/example/library/service/BookService.java src/com/example/library/util/BookFormatter.java src/com/example/library/LibraryApp.java
  1. 애플리케이션을 실행합니다.
java -cp bin com.example.library.LibraryApp

다음 출력을 볼 수 있습니다.

Library Catalog:
'The Great Gatsby' by F. Scott Fitzgerald (1925)
'To Kill a Mockingbird' by Harper Lee (1960)
'1984' by George Orwell (1949)

Found book: Book{title='1984', author='George Orwell', year=1949}

패키지 구조 이해

생성한 구조를 살펴보겠습니다.

library-app/
├── bin/                              ## 컴파일된 바이트코드
└── src/                              ## 소스 코드
    └── com/
        └── example/
            └── library/
                ├── model/            ## 데이터 구조
                │   └── Book.java
                ├── service/          ## 비즈니스 로직
                │   └── BookService.java
                ├── util/             ## 유틸리티 함수
                │   └── BookFormatter.java
                └── LibraryApp.java   ## 메인 애플리케이션

패키지 구성 원칙

이 구조는 중요한 설계 원칙을 따릅니다.

  1. 관심사 분리 (Separation of Concerns):

    • model 패키지: 데이터 구조를 포함합니다.
    • service 패키지: 비즈니스 로직을 포함합니다.
    • util 패키지: 유틸리티 함수를 포함합니다.
  2. 논리적 그룹화 (Logical Grouping): 관련 클래스는 동일한 패키지에 함께 그룹화됩니다.

  3. 직관적인 탐색 (Intuitive Navigation): 패키지 구조를 통해 특정 기능을 쉽게 찾을 수 있습니다.

  4. Import 관리: 클래스는 import 를 통해 서로 참조하여 종속성을 명확하게 합니다.

이러한 방식으로 코드를 구성하면 이해하고 확장하기 쉬운, 더 유지 관리 가능하고 확장 가능한 애플리케이션을 만들 수 있습니다.

Maven 을 사용한 프로젝트 관리

이 단계에서는 Apache Maven 을 사용하여 Java 프로젝트를 관리하는 방법을 배웁니다. Maven 은 프로젝트 설정 및 유지를 단순화하는 강력한 빌드 자동화 및 종속성 관리 도구입니다.

Maven 이해

Maven 은 다음을 제공합니다.

  • 표준 프로젝트 구조
  • 종속성 관리
  • 빌드 자동화
  • 프로젝트 정보 관리
  • 프로젝트 간 일관된 빌드 프로세스

Maven 프로젝트 설정

Maven 을 사용하여 새 프로젝트를 만들어 보겠습니다.

  1. 먼저, Maven 이 설치되었는지 확인합니다.
mvn --version

다음과 유사한 출력을 볼 수 있습니다.

Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 11.0.18, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "5.15.0-1036-azure", arch: "amd64", family: "unix"
  1. 프로젝트 디렉토리로 이동합니다.
cd /home/labex/project
  1. archetype (프로젝트 템플릿) 을 사용하여 새 Maven 프로젝트를 생성합니다.
mvn archetype:generate \
  -DgroupId=com.example.calculator \
  -DartifactId=simple-calculator \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DarchetypeVersion=1.4 \
  -DinteractiveMode=false

이 명령은 표준 디렉토리 구조를 가진 새 프로젝트를 생성합니다.

  1. 프로젝트 구조를 검토합니다.
cd simple-calculator
ls -la

다음과 유사한 출력을 볼 수 있습니다.

total 24
drwxr-xr-x 4 labex labex 4096 ... .
drwxr-xr-x 6 labex labex 4096 ... ..
-rw-r--r-- 1 labex labex  174 ... .gitignore
-rw-r--r-- 1 labex labex  720 ... pom.xml
drwxr-xr-x 4 labex labex 4096 ... src

여기서 핵심 파일은 프로젝트 구성을 정의하는 pom.xml (Project Object Model) 입니다.

  1. Maven 표준 디렉토리 레이아웃을 검토합니다.
find src -type d

다음과 같은 출력을 볼 수 있습니다.

src
src/main
src/main/java
src/main/java/com
src/main/java/com/example
src/main/java/com/example/calculator
src/test
src/test/java
src/test/java/com
src/test/java/com/example
src/test/java/com/example/calculator

이것이 Maven 표준 디렉토리 레이아웃입니다.

  • src/main/java: 소스 코드
  • src/main/resources: 리소스 파일
  • src/test/java: 테스트 코드
  • src/test/resources: 테스트 리소스
  1. 생성된 App.java 파일을 살펴보겠습니다.
cat src/main/java/com/example/calculator/App.java

간단한 "Hello World" 클래스를 볼 수 있습니다.

package com.example.calculator;

/**
 * Hello world!
 *
 */
public class App
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
    }
}

Maven 프로젝트 향상

더 많은 클래스를 추가하여 계산기 프로젝트를 향상시켜 보겠습니다.

  1. src/main/java/com/example/calculator/Calculator.java라는 새 파일을 생성합니다.
package com.example.calculator;

public class Calculator {

    public int add(int a, int b) {
        return a + b;
    }

    public int subtract(int a, int b) {
        return a - b;
    }

    public int multiply(int a, int b) {
        return a * b;
    }

    public double divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("Cannot divide by zero");
        }
        return (double) a / b;
    }
}
  1. 이제 기존 App.java 파일을 수정하여 Calculator 클래스를 사용합니다.
package com.example.calculator;

/**
 * Simple Calculator Application
 */
public class App
{
    public static void main( String[] args )
    {
        Calculator calculator = new Calculator();

        // Perform some calculations
        System.out.println("Addition: 5 + 3 = " + calculator.add(5, 3));
        System.out.println("Subtraction: 10 - 4 = " + calculator.subtract(10, 4));
        System.out.println("Multiplication: 6 * 7 = " + calculator.multiply(6, 7));
        System.out.println("Division: 20 / 4 = " + calculator.divide(20, 4));

        System.out.println("Calculator application completed successfully!");
    }
}
  1. Maven 을 사용하여 프로젝트를 빌드합니다.
mvn compile

다음으로 끝나는 출력을 볼 수 있습니다.

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
  1. 애플리케이션을 JAR 파일로 패키징합니다.
mvn package

이 명령은 코드를 컴파일하고, 테스트를 실행하고, 애플리케이션을 패키징합니다.

  1. 패키징된 애플리케이션을 실행합니다.
java -cp target/simple-calculator-1.0-SNAPSHOT.jar com.example.calculator.App

다음 출력을 볼 수 있습니다.

Addition: 5 + 3 = 8
Subtraction: 10 - 4 = 6
Multiplication: 6 * 7 = 42
Division: 20 / 4 = 5.0
Calculator application completed successfully!

Maven POM 파일 이해

Project Object Model (POM) 파일에는 프로젝트 구성이 포함되어 있습니다. 편집기에서 pom.xml 파일을 열고 구조를 검토합니다.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example.calculator</groupId>
  <artifactId>simple-calculator</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>simple-calculator</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <!-- Build configuration... -->
</project>

POM 파일의 주요 요소:

  • groupId: 조직 또는 프로젝트 식별자
  • artifactId: 프로젝트 이름
  • version: 프로젝트 버전
  • dependencies: 프로젝트에서 사용되는 외부 라이브러리
  • build: 프로젝트 빌드 구성

Maven 주요 명령어

다음은 몇 가지 필수 Maven 명령어입니다.

  • mvn compile: 소스 코드 컴파일
  • mvn test: 테스트 실행
  • mvn package: 배포 가능한 패키지 생성 (JAR, WAR)
  • mvn install: 로컬 저장소에 패키지 설치
  • mvn clean: 빌드 아티팩트 제거 (target 디렉토리)
  • mvn clean install: clean 및 install 의 조합

Maven 은 규칙, 종속성 관리 및 빌드 자동화를 제공하여 Java 프로젝트 관리를 크게 단순화했습니다. 이 표준화된 접근 방식은 개발자가 프로젝트 구조를 관리하는 대신 코드 작성에 집중할 수 있도록 돕습니다.

요약

이 Lab 에서는 실습을 통해 Java 프로젝트 구조를 관리하기 위한 필수적인 전략을 배웠습니다.

  1. 먼저, 소스 디렉토리, 패키지 및 컴파일된 코드 구성의 기본 구성 요소를 이해하면서 기본 Java 프로젝트 구조를 수동으로 생성하는 것으로 시작했습니다.

  2. 그런 다음, 모델, 서비스 및 유틸리티 패키지로 기능을 분할하여 관심사 분리를 구현하면서 적절한 패키지 구성으로 더 복잡한 프로젝트를 생성하는 단계로 나아갔습니다.

  3. 마지막으로, 종속성 관리 및 자동화된 빌드 프로세스를 통해 표준화된 Java 프로젝트를 생성하고 관리하기 위해 강력한 빌드 자동화 도구인 Maven 을 사용하는 방법을 배웠습니다.

이러한 기본적인 기술은 향후 Java 개발 작업의 견고한 기반이 될 것이며, 잘 구성되고 유지 관리 가능하며 확장 가능한 애플리케이션을 만들 수 있도록 해줍니다. 프로젝트 구조에 대한 확립된 규칙과 모범 사례를 따르면 다른 개발자와 보다 효과적으로 협업하고 더 높은 품질의 코드를 생성할 수 있습니다.