Java

안드로이드 애플리케이션 개발: Clean Architecture의 기본 원칙과 Java 예제를 통한 이해

person holding black android smartphone

먹을것들의 수많은 댓글을 통한 요청으로 안드로이드에 관련한 주제로 글을 써보려고 한다.

안드로이드 애플리케이션 개발은 다양한 아키텍처와 패턴으로 이루어진다.

그 중 Clean Architecture는 코드의 구조화와 유지보수성, 테스트 용이성을 중점으로 한 패턴이다.

이 글에서는 Clean Architecture의 기본 원칙과 Java 예제를 통해 이 아키텍처를 깊게 이해본다.

Clean Architecture란?

Clean Architecture는 애플리케이션의 구조를 여러 계층으로 나누어 각 계층이 독립적인 역할을 수행하도록 하는 아키텍처 패턴이다.

주요 계층은 다음과 같다:

  • Entity: 비즈니스 로직을 담당하는 모델 객체이다.
  • Use Cases (or Interactors): 애플리케이션의 비즈니스 로직을 정의한다.
  • Interface Adapters: 데이터 변환과 같은 인터페이스를 적용한다.
  • Frameworks and Drivers: UI, 데이터베이스, 외부 API 등의 구체적인 구현을 포함한다.

Java 예제로 Clean Architecture 이해하기

1. Entity

public class User {
    private final String id;
    private final String name;

    public User(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

2. Use Cases

public class GetUserDetailUseCase {
    private UserRepository userRepository;

    public GetUserDetailUseCase(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User execute(String userId) {
        return userRepository.getUser(userId);
    }
}

3. Interface Adapters

public interface UserRepository {
    User getUser(String userId);
    void saveUser(User user);
}

4. Frameworks and Drivers

여기서는 안드로이드 액티비티를 간단하게 예시로 들었다.

public class UserDetailActivity extends AppCompatActivity {
    private GetUserDetailUseCase getUserDetailUseCase;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_detail);
        // ... 초기화 로직
        User user = getUserDetailUseCase.execute(userId);
        displayUserDetail(user);
    }

    private void displayUserDetail(User user) {
        // UI 업데이트 로직
    }
}

Clean Architecture의 장점

  1. 독립성: 각 계층은 독립적으로 운영되므로, 변경과 테스트가 쉽다.
  2. 재사용성: 비즈니스 로직은 프레임워크나 UI와 독립적이므로 재사용이 용이하다.
  3. 유지보수성: 구조가 체계적이므로 코드의 유지보수가 쉽다.

참고하면 좋은 자료

안드로이드 공식문서이다.
천천히 읽으면서 참고하면 Clean Architecture의 전반적인 구조를 이해하기 좋다.
Android Developer – App architecture guide

NHN 밋업문서이다.
이 글과 위의 안드로이드 공식문서를 전체적으로 읽고 이해한 뒤, Clean Architecture의 개념 고도화를 위해 참고하면 좋다.
[Android] 요즘 핫한 Clean Architecture 왜 쓰는 거야?

마치며

Clean Architecture는 안드로이드 애플리케이션의 복잡성을 관리하는 데 있어 효과적인 방법이다.

개발자로서 이 아키텍처를 학습하고 실제 프로젝트에 적용하면 큰 도움이 될 것이다.

안드로이드 라이브러리 프로젝트 Fat-AAR 생성 방법 (with. kezong:fat-aar)

denny muller HfWA Axq6Ek unsplash scaled

TL;DR

// build.gradle

apply plugin: 'com.kezong.fat-aar'

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.github.kezong:fat-aar:1.3.8'
    }
}

dependencies {
    // aar 에 포함 안됨
    implementation 'libraries:havenot:includein:aar:1.0.0'
    testImplementation 'junit:junit:4.13.2'

    // aar 에 포함 될 라이브러리
    embed 'some-lib1:1.0.0'

    // aar 에 포함 될 라이브러리
    embed('some-lib2:1.0.0') {
        // some-lib2 의 하위 라이브러리도 포함시킬 지 여부
        transitive = false
        // some-lib2 의 특정 하위 라이브러리를 제외
        exclude(group:'some-group', module:'some-module')
    }
}

AAR 파일의 정의

“AAR” 파일은 안드로이드 앱을 빌드하기 위한 Android Archive의 약자이다. Android 앱 프로젝트에서 자원과 소스 코드를 패키징하여 라이브러리로 만들 때 사용되는 파일 형식이다.

AAR 파일은 JAR (Java Archive) 파일과 유사하지만 더 많은 기능을 제공한다. 일반적으로 AAR 파일은 Android 라이브러리 프로젝트를 빌드할 때 생성되며, 이 라이브러리는 다른 Android 앱 프로젝트에서 재사용할 수 있다.

AAR 파일에는 앱의 자원 (레이아웃, 이미지 등)과 소스 코드 (.class 파일), AndroidManifest.xml 파일, 그리고 프로젝트가 의존하는 라이브러리들과 관련된 정보가 포함된다. 이를 통해 라이브러리 개발자는 라이브러리를 다른 앱 개발자들과 공유하고, 더 쉽게 앱에 통합할 수 있도록 도와준다.

AAR 파일은 Android Studio 등의 개발 도구에서 사용되며, 라이브러리 프로젝트를 빌드하여 생성할 수 있다.

Fat-AAR 파일의 정의

라이브러리를 사용하다보면, 하나 이상의 라이브러리를 포함하는 AAR이 필요할 수 있다. 이를 Fat-AAR 이라고 한다.

AAR 에는 라이브러리 JAR 과 Drawable, Layout 등과 같은 리소스가 포함되어 있을 수 있다. Fat-AAR 에는 둘 이상의 AAR 이 포함되어 있으므로 많은 라이브러리를 가져올 필요가 없으며, 필요한 모든 것을 포함하는 라이브러리만 가져올 수 있다.

Fat-AAR 생성 방법

Fat-AAR 생성 방법은 fat jar를 생성하는 방법에 대해서는 간단한 검색으로 바로 구현할 수 있을 만큼 다양한 레퍼런스가 있지만, fat aar을 생성하는 방법은 상세하게 나오지 않아 구현에 어려움이 있다.

아래의 방법은 fat-aar-android (fat-aar) 라이브러리를 사용한다.

라이브러리를 fat aar 을 생성할 프로젝트의 빌드 스크립트에 추가한다.
글 작성 날짜(2023/07/25) 기준 최신 버전 1.3.8 사용.

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.github.kezong:fat-aar:1.3.8'
    }
}

이후 빌드 스크립트 최상단에 아래의 줄을 추가하여 플러그인을 적용한다.

apply plugin: 'com.kezong.fat-aar'

dependencies 에서 빌드된 aar 파일에 포함시킬 라이브러리를 골라 implementation 을 embed 로 변경한다.

dependencies {
    // aar 에 포함 안됨
    implementation 'libraries:havenot:includein:aar:1.0.0'
    testImplementation 'junit:junit:4.13.2'

    // aar 에 포함 될 라이브러리
    embed 'some-lib1:1.0.0'

    // aar 에 포함 될 라이브러리
    embed('some-lib2:1.0.0') {
        // some-lib2 의 하위 라이브러리도 포함시킬 지 여부
        transitive = false
        // some-lib2 의 특정 하위 라이브러리를 제외
        exclude(group:'some-group', module:'some-module')
    }
}

위와 같이 빌드 스크립트를 설정하고 gradle assemble 을 실행시킨 뒤, 결과물을 압축해제하면 라이브러리가 정상적으로 임베딩된것을 확인할 수 있다.

fat aar result

(junit 을 embed 선언 했을 때)

주의사항

  1. Gradle 버전 8 이상의 프로젝트에서는 동작하지 않으므로, Gradle 버전을 8 미만으로 낮추어야 한다.
    관련링크
  2. 리소스 ID 끼리 충돌이 날 수 있으므로, 가능한 경우 앞에 접두사를 붙여 다른 라이브러리 내의 리소스 ID와 충돌을 피하는 것이 좋다.
  3. ProGuard를 사용하고 minifyEnabled 값이 true로 설정되어 있을 경우, 외부 라이브러리가 필터링되어 빌드 결과물에 포함되지 않을 수 있으므로, ProGuard 룰을 다시 한 번 살펴보아야 한다.