Communitygithub.com

android-clean-architecture

Padrões de Clean Architecture para projetos Android e Kotlin Multiplatform — estrutura de módulos, regras de dependência, UseCases, Repositories e padrões da camada de dados. Use ao estruturar módulos, camadas ou fluxo de dados em um projeto Android ou KMP.

O que é android-clean-architecture?

Este skill fornece diretrizes detalhadas para aplicar Clean Architecture em projetos Android e Kotlin Multiplatform (KMP). Ele define uma estrutura de módulos clara, como `domain`, `data` e `presentation`, com regras de dependência rigorosas: a camada `domain` nunca depende de frameworks, mantendo-se puramente Kotlin. O skill inclui padrões práticos como UseCases (com `operator fun invoke`), Repositories com mapeamento entre entidades locais/remotas, e fontes de dados para Room (Android), SQLDelight (KMP) e Ktor para rede. Também aborda injeção de dependência com Koin e Hilt, tratamento de erros usando `Result` ou Tipos selados, e plugins de convenção Gradle para reduzir duplicação. Ao evitar anti-padrões como expor entidades de banco de dados à UI ou colocar lógica de negócios em ViewModels, este skill ajuda a construir apps modulares, testáveis e escaláveis.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/android-clean-architecture

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Clean Architecture para Android

Padrões de Clean Architecture para projetos Android e KMP. Aborda limites de módulos, inversão de dependências, padrões UseCase/Repository e design da camada de dados com Room, SQLDelight e Ktor.

Quando Ativar

  • Estruturando módulos de projetos Android ou KMP
  • Implementando UseCases, Repositories ou DataSources
  • Projetando fluxo de dados entre camadas (domain, data, presentation)
  • Configurando injeção de dependência com Koin ou Hilt
  • Trabalhando com Room, SQLDelight ou Ktor em uma arquitetura em camadas

Estrutura de Módulos

Layout Recomendado

project/
├── app/                  # Ponto de entrada Android, fiação DI, classe Application
├── core/                 # Utilitários compartilhados, classes base, tipos de erro
├── domain/               # UseCases, modelos de domínio, interfaces de repositório (Kotlin puro)
├── data/                 # Implementações de repositório, DataSources, BD, rede
├── presentation/         # Telas, ViewModels, modelos de UI, navegação
├── design-system/        # Componentes Compose reutilizáveis, tema, tipografia
└── feature/              # Módulos de funcionalidade (opcional, para projetos maiores)
    ├── auth/
    ├── settings/
    └── profile/

Regras de Dependência

app → presentation, domain, data, core
presentation → domain, design-system, core
data → domain, core
domain → core (ou nenhuma dependência)
core → (nada)

Crítico: domain NUNCA deve depender de data, presentation ou qualquer framework. Contém apenas Kotlin puro.

Camada de Domínio

Padrão UseCase

Cada UseCase representa uma operação de negócio. Use operator fun invoke para pontos de chamada limpos:

class GetItemsByCategoryUseCase(
    private val repository: ItemRepository
) {
    suspend operator fun invoke(category: String): Result<List<Item>> {
        return repository.getItemsByCategory(category)
    }
}

// UseCase baseado em Flow para streams reativos
class ObserveUserProgressUseCase(
    private val repository: UserRepository
) {
    operator fun invoke(userId: String): Flow<UserProgress> {
        return repository.observeProgress(userId)
    }
}

Modelos de Domínio

Modelos de domínio são classes de dados Kotlin puras — sem anotações de framework:

data class Item(
    val id: String,
    val title: String,
    val description: String,
    val tags: List<String>,
    val status: Status,
    val category: String
)

enum class Status { DRAFT, ACTIVE, ARCHIVED }

Interfaces de Repositório

Definidas no domínio, implementadas nos dados:

interface ItemRepository {
    suspend fun getItemsByCategory(category: String): Result<List<Item>>
    suspend fun saveItem(item: Item): Result<Unit>
    fun observeItems(): Flow<List<Item>>
}

Camada de Dados

Implementação do Repositório

Coordena entre fontes de dados locais e remotas:

class ItemRepositoryImpl(
    private val localDataSource: ItemLocalDataSource,
    private val remoteDataSource: ItemRemoteDataSource
) : ItemRepository {

    override suspend fun getItemsByCategory(category: String): Result<List<Item>> {
        return runCatching {
            val remote = remoteDataSource.fetchItems(category)
            localDataSource.insertItems(remote.map { it.toEntity() })
            localDataSource.getItemsByCategory(category).map { it.toDomain() }
        }
    }

    override suspend fun saveItem(item: Item): Result<Unit> {
        return runCatching {
            localDataSource.insertItems(listOf(item.toEntity()))
        }
    }

    override fun observeItems(): Flow<List<Item>> {
        return localDataSource.observeAll().map { entities ->
            entities.map { it.toDomain() }
        }
    }
}

Padrão Mapper

Mantenha os mappers como funções de extensão próximas aos modelos de dados:

// Na camada de dados
fun ItemEntity.toDomain() = Item(
    id = id,
    title = title,
    description = description,
    tags = tags.split("|"),
    status = Status.valueOf(status),
    category = category
)

fun ItemDto.toEntity() = ItemEntity(
    id = id,
    title = title,
    description = description,
    tags = tags.joinToString("|"),
    status = status,
    category = category
)

Room Database (Android)

@Entity(tableName = "items")
data class ItemEntity(
    @PrimaryKey val id: String,
    val title: String,
    val description: String,
    val tags: String,
    val status: String,
    val category: String
)

@Dao
interface ItemDao {
    @Query("SELECT * FROM items WHERE category = :category")
    suspend fun getByCategory(category: String): List<ItemEntity>

    @Upsert
    suspend fun upsert(items: List<ItemEntity>)

    @Query("SELECT * FROM items")
    fun observeAll(): Flow<List<ItemEntity>>
}

SQLDelight (KMP)

-- Item.sq
CREATE TABLE ItemEntity (
    id TEXT NOT NULL PRIMARY KEY,
    title TEXT NOT NULL,
    description TEXT NOT NULL,
    tags TEXT NOT NULL,
    status TEXT NOT NULL,
    category TEXT NOT NULL
);

getByCategory:
SELECT * FROM ItemEntity WHERE category = ?;

upsert:
INSERT OR REPLACE INTO ItemEntity (id, title, description, tags, status, category)
VALUES (?, ?, ?, ?, ?, ?);

observeAll:
SELECT * FROM ItemEntity;

Cliente de Rede Ktor (KMP)

class ItemRemoteDataSource(private val client: HttpClient) {

    suspend fun fetchItems(category: String): List<ItemDto> {
        return client.get("api/items") {
            parameter("category", category)
        }.body()
    }
}

// Configuração do HttpClient com negociação de conteúdo
val httpClient = HttpClient {
    install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true }) }
    install(Logging) { level = LogLevel.HEADERS }
    defaultRequest { url("https://api.example.com/") }
}

Injeção de Dependência

Koin (compatível com KMP)

// Módulo de domínio
val domainModule = module {
    factory { GetItemsByCategoryUseCase(get()) }
    factory { ObserveUserProgressUseCase(get()) }
}

// Módulo de dados
val dataModule = module {
    single<ItemRepository> { ItemRepositoryImpl(get(), get()) }
    single { ItemLocalDataSource(get()) }
    single { ItemRemoteDataSource(get()) }
}

// Módulo de apresentação
val presentationModule = module {
    viewModelOf(::ItemListViewModel)
    viewModelOf(::DashboardViewModel)
}

Hilt (somente Android)

@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
    @Binds
    abstract fun bindItemRepository(impl: ItemRepositoryImpl): ItemRepository
}

@HiltViewModel
class ItemListViewModel @Inject constructor(
    private val getItems: GetItemsByCategoryUseCase
) : ViewModel()

Tratamento de Erros

Padrão Result/Try

Use Result<T> ou um tipo selado personalizado para propagação de erros:

sealed interface Try<out T> {
    data class Success<T>(val value: T) : Try<T>
    data class Failure(val error: AppError) : Try<Nothing>
}

sealed interface AppError {
    data class Network(val message: String) : AppError
    data class Database(val message: String) : AppError
    data object Unauthorized : AppError
}

// No ViewModel — mapear para estado da UI
viewModelScope.launch {
    when (val result = getItems(category)) {
        is Try.Success -> _state.update { it.copy(items = result.value, isLoading = false) }
        is Try.Failure -> _state.update { it.copy(error = result.error.toMessage(), isLoading = false) }
    }
}

Plugins de Convenção (Gradle)

Para projetos KMP, use plugins de convenção para reduzir duplicação de arquivos de build:

// build-logic/src/main/kotlin/kmp-library.gradle.kts
plugins {
    id("org.jetbrains.kotlin.multiplatform")
}

kotlin {
    androidTarget()
    iosX64(); iosArm64(); iosSimulatorArm64()
    sourceSets {
        commonMain.dependencies { /* deps compartilhadas */ }
        commonTest.dependencies { implementation(kotlin("test")) }
    }
}

Aplicar nos módulos:

// domain/build.gradle.kts
plugins { id("kmp-library") }

Anti-Padrões a Evitar

  • Importar classes do framework Android no domain — mantenha-o Kotlin puro
  • Expor entidades de banco de dados ou DTOs para a camada de UI — sempre mapeie para modelos de domínio
  • Colocar lógica de negócios em ViewModels — extraia para UseCases
  • Usar GlobalScope ou corrotinas não estruturadas — use viewModelScope ou concorrência estruturada
  • Implementações de repositório inchadas — divida em DataSources focados
  • Dependências circulares entre módulos — se A depende de B, B não deve depender de A

Referências

Consulte skill: compose-multiplatform-patterns para padrões de UI. Consulte skill: kotlin-coroutines-flows para padrões assíncronos.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Habilidades Relacionadas