아키텍처

안드로이드 애플리케이션 개발: 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는 안드로이드 애플리케이션의 복잡성을 관리하는 데 있어 효과적인 방법이다.

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

iOS 아키텍처 패턴 – 5: RIB’s

black iPad

iOS 애플리케이션 개발에서는 여러 아키텍처 패턴들이 사용된다.

그 중 RIB’s (Router, Interactor, Builder)는 Uber에서 소개된 아키텍처로, 확장성과 테스트 용이성을 중점으로 한 패턴이다.

이 글에서는 RIB’s의 기본 개념과 Swift를 이용한 예제를 통해 이 패턴을 자세히 알아본다.

RIB’s란?

RIB’s는 Router, Interactor, Builder의 약자로 다음과 같은 역할을 한다:

  • Router: 화면 전환과 같은 뷰의 네비게이션 로직을 담당한다.
  • Interactor: 비즈니스 로직을 담당한다.
  • Builder: RIB의 인스턴스 생성과 의존성 주입을 담당한다.

Swift 예제로 MVC 이해하기

1. Interactor

protocol ProfileInteractable: AnyObject {
    func fetchUserProfile() -> UserProfile
}

class ProfileInteractor: ProfileInteractable {
    func fetchUserProfile() -> UserProfile {
        // API 호출이나 데이터베이스 조회 등의 로직
        return UserProfile(name: "John Doe", age: 25)
    }
}

2. Router

protocol ProfileRoutable: AnyObject {
    func routeToDetailScreen(userProfile: UserProfile)
}

class ProfileRouter: ProfileRoutable {
    func routeToDetailScreen(userProfile: UserProfile) {
        // 상세 화면으로의 라우팅 로직
    }
}

3. Builder

class ProfileBuilder {
    static func build() -> ProfileViewController {
        let interactor = ProfileInteractor()
        let router = ProfileRouter()
        let viewController = ProfileViewController(interactor: interactor, router: router)
        return viewController
    }
}

4. View Controller

UIKit을 사용하여 간단한 예제를 구현했다.

import UIKit

class ProfileViewController: UIViewController {
    private let interactor: ProfileInteractable
    private let router: ProfileRoutable

    init(interactor: ProfileInteractable, router: ProfileRoutable) {
        self.interactor = interactor
        self.router = router
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // ViewController 로직 (예: 버튼 액션 등)
}

RIB’s의 장점

  1. 모듈화: RIB’s는 애플리케이션을 독립적인 모듈로 분리하므로, 확장성과 유지보수가 쉽다.
  2. 재사용성: 비즈니스 로직과 라우팅 로직이 분리되어 있어 재사용이 용이하다.
  3. 테스트 용이성: 각 컴포넌트가 독립적이므로 단위 테스트하기 쉽다.

마치며

RIB’s는 큰 규모의 프로젝트나 복잡한 네비게이션 구조를 가진 애플리케이션에 특히 적합한 아키텍처 패턴이다.

이 패턴을 통해 iOS 애플리케이션의 구조와 코드 품질을 개선할 수 있다.

개발자로서 RIB’s를 학습하고 여러 프로젝트에 적용해보면 더욱 큰 경험을 얻을 수 있을 것이다.

iOS 아키텍처 패턴 – 4: VIPER

a computer monitor sitting on top of a wooden desk

iOS 개발의 세계에는 다양한 아키텍처 패턴이 존재한다.

이 중에서도 VIPER는 크고 복잡한 프로젝트에서 코드의 구조와 관리를 개선하기 위해 도입되는 아키텍처 중 하나이다.

이 글에서는 VIPER의 구성 요소와 Swift 예제를 통해 이 패턴을 깊게 이해해보도록 한다.

VIPER란?

VIPER는 View, Interactor, Presenter, Entity, Router의 약자로, 각 구성 요소는 다음과 같은 역할을 담당한다.

  • View: 사용자에게 보여지는 UI 요소를 담당한다.
  • Interactor: 비즈니스 로직을 수행한다.
  • Presenter: View와 Interactor 사이에서 데이터를 변환하고 조정한다.
  • Entity: 애플리케이션의 기본 데이터 객체이다.
  • Router: 화면 간의 전환 로직을 담당한다.

Swift 예제로 VIPER 이해하기

1. Entity

struct Article {
    let title: String
    let content: String
}

2. Interactor

protocol ArticleInteractorProtocol {
    func fetchArticles() -> [Article]
}

class ArticleInteractor: ArticleInteractorProtocol {
    func fetchArticles() -> [Article] {
        // 여기서 데이터베이스 또는 API로부터 데이터를 가져온다.
        return [Article(title: "Sample Title", content: "Sample Content")]
    }
}

3. Presenter

protocol ArticlePresenterProtocol {
    func viewDidLoad()
}

class ArticlePresenter: ArticlePresenterProtocol {
    var view: ArticleViewProtocol?
    var interactor: ArticleInteractorProtocol?
    var router: ArticleRouterProtocol?

    func viewDidLoad() {
        let articles = interactor?.fetchArticles()
        view?.displayArticles(articles ?? [])
    }
}

4. View

SwiftUI를 사용하여 간단한 예제를 구현했다.

protocol ArticleViewProtocol: AnyObject {
    func displayArticles(_ articles: [Article])
}

import SwiftUI

struct ArticleView: View, ArticleViewProtocol {
    var presenter: ArticlePresenterProtocol?

    var body: some View {
        // UI 구성
    }

    func displayArticles(_ articles: [Article]) {
        // UI 업데이트 로직
    }
}

5. Router

protocol ArticleRouterProtocol {
    func navigateToDetail(article: Article)
}

class ArticleRouter: ArticleRouterProtocol {
    func navigateToDetail(article: Article) {
        // 상세 화면으로의 전환 로직
    }
}

VIPER의 장점

  1. 단일 책임 원칙: 각 모듈은 자신의 역할에만 집중한다. 이로 인해 코드의 품질과 유지보수성이 향상된다.
  2. 테스트 용이성: 각 구성 요소는 독립적이므로 단위 테스트하기 쉽다.
  3. 모듈화: VIPER는 모듈화를 장려하여, 팀원 간의 협업이 더욱 원활해진다.

마치며

VIPER는 iOS 애플리케이션의 복잡도를 효과적으로 관리할 수 있는 강력한 아키텍처 패턴이다.

큰 프로젝트나 팀으로의 개발 시에 특히 유용하므로, 개발자로서 이 패턴을 학습하고 경험하는 것은 큰 자산이 될 것이다.

iOS 아키텍처 패턴 – 3: MVP

a blurry image of a computer screen with text

iOS 애플리케이션 개발은 수많은 디자인 패턴과 아키텍처 스타일로 이루어진다.

MVVM와 MVC에 이어, MVP (Model-View-Presenter)는 iOS 개발에서 사용되는 또 다른 중요한 패턴 중 하나이다.

이 글에서는 MVP 패턴의 핵심 개념과 Swift 예제 코드를 통해 이 아키텍처의 매력을 소개한다.

MVP란?

MVP는 Model, View, Presenter의 약자로, 이 세 가지 구성 요소로 애플리케이션을 구조화하는 디자인 패턴이다.

  • Model: 데이터와 비즈니스 로직을 담당한다.
  • View: 사용자에게 보여지는 UI 요소이다. 사용자의 입력을 받아 Presenter에 전달한다.
  • Presenter: View와 Model 사이의 중재자 역할을 하며, 로직을 수행하고 View에 결과를 전달한다.

Swift 예제로 MVP 이해하기

1. Model

struct Task {
    let title: String
    var isCompleted: Bool
}

2. View

protocol TaskViewProtocol: AnyObject {
    func displayTasks(_ tasks: [Task])
}

3. Presenter

class TaskPresenter {
    weak var view: TaskViewProtocol?
    var tasks: [Task] = []

    func addTask(title: String) {
        let newTask = Task(title: title, isCompleted: false)
        tasks.append(newTask)
        view?.displayTasks(tasks)
    }

    func toggleTaskCompletion(at index: Int) {
        tasks[index].isCompleted.toggle()
        view?.displayTasks(tasks)
    }
}

4. View Implementation

UIKit을 사용하여 간단한 예제를 구현했다.

import UIKit

class TaskViewController: UIViewController, TaskViewProtocol {
    var presenter: TaskPresenter?

    // TableView, Buttons, 등의 UI 요소 선언.

    func displayTasks(_ tasks: [Task]) {
        // 주어진 tasks 파라미터를 통해 UI를 업데이트 한다.
    }

    // 사용자 상호 작용을 처리하고 적절한 발표자 메서드를 호출한다.
}

MVP의 장점

  1. 명확한 분리: MVP는 로직과 UI의 분리를 명확하게 한다. 이로 인해 유닛 테스트가 더 쉬워진다.
  2. 재사용성: Presenter는 UI 플랫폼에 독립적이므로 다양한 View에서 재사용할 수 있다.
  3. 유연성: 애플리케이션의 기능 확장이나 변경이 필요할 때, 각 부분을 독립적으로 수정하거나 추가할 수 있다.

마치며

MVP는 iOS 애플리케이션 개발에서 효과적인 아키텍처 패턴 중 하나이다.

MVC나 MVVM과는 다르게, MVP는 View와 로직을 더욱 철저하게 분리하여 개발 및 테스팅의 효율성을 높인다.

iOS 개발을 공부하는 개발자들에게 MVP 패턴의 적용은 필수적인 경험이 될 것이다.

iOS 아키텍처 패턴 – 2: MVC

black flat screen computer monitor

iOS 애플리케이션 개발을 시작할 때 가장 기본적으로 알아야 할 아키텍처 패턴은 바로 MVC (Model-View-Controller)다.

이 글에서는 MVC 패턴의 기본 개념과 Swift 예제 코드를 통해 MVC의 구조를 이해하는 데 도움을 줄 것이다.

MVC란?

MVC는 Model, View, Controller의 약자로, 이 세 가지 구성 요소로 애플리케이션을 구조화하는 디자인 패턴이다.

  • Model: 데이터와 비즈니스 로직을 담당한다.
  • View: 사용자에게 보여지는 UI 요소이다.
  • Controller: Model과 View 사이의 중재자 역할을 한다. 사용자의 입력을 받아 Model을 변경하고, Model의 변경사항을 View에 반영한다.

Swift 예제로 MVC 이해하기

1. Model

struct Book {
    let title: String
    let author: String
}

2. Controller

class BookController {
    var books: [Book] = []

    func addBook(title: String, author: String) {
        let newBook = Book(title: title, author: author)
        books.append(newBook)
        // View 업데이트 로직
    }

    func removeBook(at index: Int) {
        books.remove(at: index)
        // View 업데이트 로직
    }
}

3. View

UIKit을 사용하여 간단한 예제를 구현했다.

import UIKit

class BookViewController: UIViewController {
    var bookController = BookController()

    // 여기에 TableView나 다른 UI 요소들을 정의하고, 사용자의 입력을 받아 Controller에 전달하는 로직을 구현.
}

MVC의 장점

  1. 분리된 책임: Model, View, Controller 각각의 역할이 명확하게 분리되어 있다.
  2. 재사용성: Model과 View는 재사용이 가능하며, 다양한 Controller와 함께 사용될 수 있다.
  3. 확장성: 애플리케이션의 기능이 확장되어도 각 부분을 독립적으로 관리할 수 있어 유지보수가 용이하다.

주의점

MVC 패턴은 잘못 사용될 경우 Controller가 과도하게 커질 수 있다.

이를 “Massive View Controller” 문제라고 부르며, 이를 피하기 위해 다른 아키텍처 패턴들 (예: MVVM, VIPER)이 제안되기도 했다.

마치며

MVC는 iOS 애플리케이션 개발의 기본적인 아키텍처 패턴이다.

올바르게 사용될 경우 강력하고 유연한 애플리케이션 구조를 제공한다.

iOS 개발의 세계에 발을 들이는 개발자들은 MVC의 기본 원칙을 잘 이해하고, 다양한 프로젝트에 적용해보길 권장한다.

iOS 아키텍처 패턴 – 1: MVVM

multicolored text

애플의 iOS는 전세계적으로 수백만의 사용자들이 사용하는 모바일 운영체제 중 하나이다.

따라서 iOS 애플리케이션을 개발하는 것은 많은 책임을 수반한다.

효율적이고 관리하기 쉬운 코드를 작성하기 위해 여러 아키텍처 패턴이 있다.

그 중에서도 MVVM (Model-View-ViewModel)은 현대 iOS 개발자들에게 인기있는 선택 중 하나다.

MVVM이란?

MVVM은 Model-View-ViewModel의 약자로, UI 로직과 비즈니스 로직을 분리하여 코드의 가독성과 재사용성을 높이는 디자인 패턴이다.

  • Model: 데이터와 비즈니스 로직을 담당한다.
  • View: 사용자에게 보여지는 UI 요소이다.
  • ViewModel: View와 Model 사이의 다리 역할을 한다. 사용자의 액션에 따라 Model을 업데이트하고, Model의 변경사항을 View에 반영한다.

Swift 예제로 MVVM 이해하기

1. Model

struct User {
    let name: String
    let age: Int
}

2. ViewModel

class UserViewModel {
    private var user: User

    var displayName: String {
        return "이름: \(user.name)"
    }

    var displayAge: String {
        return "나이: \(user.age)세"
    }

    init(user: User) {
        self.user = user
    }
}

3. View

SwiftUI를 사용하여 간단한 예제를 구현했다.

import SwiftUI

struct UserView: View {
    @ObservedObject var viewModel: UserViewModel

    var body: some View {
        VStack {
            Text(viewModel.displayName)
            Text(viewModel.displayAge)
        }
    }
}

MVVM의 장점

  1. 재사용성: ViewModel은 platform-independent하므로 다양한 View에서 재사용이 가능하다.
  2. 테스트 용이성: ViewModel은 UI 요소와 독립적이므로 단위 테스트하기 용이하다.
  3. 분리: 로직과 UI가 분리되어 있어, 각각의 부분에 대한 유지보수가 쉽다.

마치며

MVVM은 iOS 개발에서 코드의 구조와 관리를 개선하기 위한 훌륭한 방법 중 하나이다.

애플리케이션의 복잡도가 증가함에 따라 MVVM 같은 아키텍처 패턴의 중요성은 더욱 커질 것이다.

MVVM을 적용하여 더 나은 iOS 애플리케이션을 개발해보길 바란다.