UseCase Best Practices in Kotlin

Kotlin Tutorial

UseCase Best Practices in Kotlin (Clean Architecture Guide)

If you’re building Android or backend applications using Clean Architecture, you’ve probably heard about UseCases (also called Interactors).

UseCases are one of the most important parts of Clean Architecture. When implemented correctly, they:

  • Keep business logic clean

  • Improve testability

  • Reduce coupling

  • Make code easier to maintain

  • Improve scalability

In this beginner-friendly guide, you’ll learn:

  • What a UseCase is in Kotlin

  • Why UseCases are important

  • Where UseCases fit in Clean Architecture

  • Best practices for writing UseCases

  • Common mistakes

  • Real-world examples

  • Testing strategies

Let’s get started


What Is a UseCase in Clean Architecture?

A UseCase represents a single piece of business logic in your application.

Think of it as:

One action your application can perform.

Examples:

  • LoginUserUseCase

  • GetUserProfileUseCase

  • AddToCartUseCase

  • SubmitOrderUseCase

Each UseCase should have one clear responsibility.


Where Do UseCases Fit in Clean Architecture?

In Clean Architecture, UseCases belong to the Domain Layer.

Typical structure:

- presentation/
- domain/
- model/
- repository/
- usecase/
- data/

The dependency rule says:

  • Presentation depends on Domain

  • Data depends on Domain

  • Domain depends on nothing

UseCases should not depend on Android, Retrofit, Room, or any framework.


Basic Example of a UseCase

The UseCase:

  • Calls repository

  • Applies business rules

  • Returns domain model

It contains no UI code.


Why UseCases Are Important

Without UseCases, developers often:

  • Put business logic inside ViewModel

  • Mix UI and domain logic

  • Create tightly coupled code

UseCases solve this by:

  •  Separating concerns
  •  Improving testability
  •  Encouraging single responsibility
  •  Making code reusable

UseCase Best Practices (Step-by-Step)

Let’s explore the most important best practices.


 One UseCase = One Responsibility

Each UseCase should do only one thing.

 Bad Example:

Too many responsibilities.


Good Example:

Each class handles one action.


Keep UseCases Framework-Free

UseCases should NOT import:

  • Android classes

  • ViewModel

  • Context

  • Retrofit

  • Room

 Avoid this:

Domain layer must remain pure Kotlin.


Inject Repository Interfaces, Not Implementations

UseCases depend on interfaces.

Inject implementation from data layer.

This follows Dependency Inversion Principle.


 Use Operator Function for Clean Syntax

Kotlin allows using operator fun invoke().

Instead of:

Use:

Example:

Cleaner and more idiomatic Kotlin.


Handle Errors Inside UseCase

Business-level errors should be handled in UseCase.

Example:

Do not let UI handle business logic errors.


 Keep UseCases Small and Focused

A UseCase should be short and readable.

If it grows too large:

  • Split it

  • Extract helper classes

Clean code is maintainable code.


Use Data Models from Domain Layer

Avoid passing API models to UseCases.

 Bad:

 Good:

Domain models should be independent.


Make UseCases Easy to Test

UseCases should be:

  • Simple

  • Independent

  • Easy to mock dependencies

Example test:


 

No Android dependencies needed.


Real-World Example – Login Flow

UseCase:

ViewModel:


 

Business validation stays inside UseCase.


Common Beginner Mistakes

 Putting Business Logic in ViewModel

Move it to UseCase.


Creating Too Many Dependencies

Keep UseCase lightweight.


Combining Multiple Responsibilities

One UseCase, one action.


 Using Android Context in Domain Layer

Never import Android in domain.


UseCase vs Repository

FeatureUseCaseRepository
Contains business rulesYesNo
Handles data sourceNoYes
Calls API/DatabaseNoYes
Used by ViewModelYesNo

UseCase orchestrates. Repository fetches data.


Naming Conventions for UseCases

Follow consistent naming:

  • Verb + Entity + UseCase

  • LoginUserUseCase

  • GetProductListUseCase

  • UpdateProfileUseCase

Avoid generic names like:

  • Manager

  • Handler

  • Processor

Be explicit.


Advanced UseCase Patterns

UseCase with Parameters Data Class


 

Improves scalability.


When Should You Use UseCases?

Use UseCases when:

  • Following Clean Architecture

  • Working on medium/large apps

  • Needing testable business logic

  • Working in teams

Avoid unnecessary complexity for tiny apps.


Frequently Asked Questions (FAQs)

1. What is a UseCase in Clean Architecture?

A UseCase represents a single piece of business logic in the domain layer.

2. Should UseCases contain Android code?

No, UseCases must remain framework-independent.

3. Why use operator invoke in UseCase?

It improves readability and provides cleaner syntax.

4. How many responsibilities should a UseCase have?

Only one responsibility.

5. Are UseCases mandatory in small projects?

Not mandatory, but recommended for scalability.


Conclusion

UseCases are the backbone of Clean Architecture in Kotlin.

You learned:

  • What UseCases are

  • Where they belong

  • Best practices

  • Common mistakes

  • Testing strategies

Mastering UseCase design will make your applications cleaner, more testable, and scalable.

You may also like...