<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Valerii Popov</title>
    <description>The latest articles on DEV Community by Valerii Popov (@inoshishi).</description>
    <link>https://dev.to/inoshishi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2269540%2Fb569ef56-6050-44aa-8131-c190daa99dce.png</url>
      <title>DEV Community: Valerii Popov</title>
      <link>https://dev.to/inoshishi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/inoshishi"/>
    <language>en</language>
    <item>
      <title>Sealed Interfaces vs. Sealed Classes in Kotlin: When and Why to Use Each</title>
      <dc:creator>Valerii Popov</dc:creator>
      <pubDate>Thu, 31 Oct 2024 10:07:19 +0000</pubDate>
      <link>https://dev.to/inoshishi/sealed-interfaces-vs-sealed-classes-in-kotlin-when-and-why-to-use-each-22m5</link>
      <guid>https://dev.to/inoshishi/sealed-interfaces-vs-sealed-classes-in-kotlin-when-and-why-to-use-each-22m5</guid>
      <description>&lt;p&gt;Kotlin’s sealed classes are widely used to create closed hierarchies, especially when representing UI states or other fixed types. But with the introduction of sealed interfaces in Kotlin 1.5, developers now have another powerful tool for structuring type-safe hierarchies. Both allow for exhaustive when expressions and ensure type safety, but they serve slightly different purposes and shine in different contexts. Let’s explore when and why to use sealed classes versus sealed interfaces in Kotlin, with practical examples, including Android UI components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sealed Classes in Kotlin
&lt;/h2&gt;

&lt;p&gt;Sealed classes are ideal when you need a limited set of subclasses that represent specific states, often within a single context. A sealed class hierarchy allows you to create a closed set of subclasses—meaning no other classes outside this file can extend the sealed class. This is especially useful for representing states in a when expression, ensuring every possible subclass is accounted for at compile time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: UI State Representation with Sealed Classes&lt;/strong&gt;&lt;br&gt;
In Android development, sealed classes are a common choice for handling UI state. Let’s imagine a simple loading screen that can display three possible states: Loading, Success, or Error. Here’s how you might implement this with a sealed class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sealed class UiState {
    object Loading : UiState()
    data class Success(val data: String) : UiState()
    data class Error(val message: String) : UiState()
}

fun handleUiState(uiState: UiState) {
    when (uiState) {
        is UiState.Loading -&amp;gt; showLoadingSpinner()
        is UiState.Success -&amp;gt; showData(uiState.data)
        is UiState.Error -&amp;gt; showError(uiState.message)
    }
}

fun showLoadingSpinner() { /* Show loading spinner */ }
fun showData(data: String) { /* Display data */ }
fun showError(message: String) { /* Show error message */ }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;UiState&lt;/code&gt; sealed class represents a closed hierarchy where only specific states (Loading, Success, and Error) are valid.&lt;br&gt;
The when expression in &lt;code&gt;handleUiState&lt;/code&gt; ensures that all states are handled exhaustively, giving us compile-time safety.&lt;br&gt;
Sealed classes are well-suited to representing UI states because they provide clear and structured representations of finite states, making it easier to reason about the different UI scenarios.&lt;/p&gt;
&lt;h2&gt;
  
  
  Sealed Interfaces in Kotlin
&lt;/h2&gt;

&lt;p&gt;Sealed interfaces, introduced in Kotlin 1.5, add flexibility to sealed hierarchies. Unlike sealed classes, which enforce a single superclass, sealed interfaces allow you to combine multiple types, as Kotlin supports multiple interfaces but only single inheritance for classes. This makes sealed interfaces a great choice for flexible hierarchies where shared behavior is needed across unrelated types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Shared ViewHolder Types with Sealed Interfaces&lt;/strong&gt;&lt;br&gt;
Let’s say we’re building an app that displays different items in a &lt;code&gt;RecyclerView&lt;/code&gt; list, and each item type has a unique &lt;code&gt;ViewHolder&lt;/code&gt;. We could use sealed interfaces to define shared behavior among &lt;code&gt;ViewHolders&lt;/code&gt;, allowing flexibility while ensuring that only specific types implement the interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sealed interface ListItem

data class TextItem(val text: String) : ListItem
data class ImageItem(val imageUrl: String) : ListItem
data class VideoItem(val videoUrl: String) : ListItem

abstract class ListItemViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    abstract fun bind(item: ListItem)
}

class TextItemViewHolder(view: View) : ListItemViewHolder(view) {
    override fun bind(item: ListItem) {
        if (item is TextItem) {
            // Bind text item data
        }
    }
}

class ImageItemViewHolder(view: View) : ListItemViewHolder(view) {
    override fun bind(item: ListItem) {
        if (item is ImageItem) {
            // Bind image item data
        }
    }
}

class VideoItemViewHolder(view: View) : ListItemViewHolder(view) {
    override fun bind(item: ListItem) {
        if (item is VideoItem) {
            // Bind video item data
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example:&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ListItem&lt;/code&gt; sealed interface defines a set of allowed item types (TextItem, ImageItem, VideoItem).&lt;br&gt;
Each item type is flexible and can be combined with other interfaces if needed, making the sealed interface versatile.&lt;br&gt;
&lt;code&gt;ListItemViewHolder&lt;/code&gt; subclasses each handle a specific type of item, enabling shared behavior without enforcing a strict hierarchy.&lt;br&gt;
This structure is especially useful for &lt;code&gt;RecyclerView&lt;/code&gt;, where flexibility and type-safety are often needed to handle diverse item types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Between Sealed Classes and Sealed Interfaces
&lt;/h2&gt;

&lt;p&gt;Understanding when to use sealed classes versus sealed interfaces largely depends on the use case:&lt;/p&gt;

&lt;p&gt;Use Sealed Classes for fixed, finite states where each subclass represents a distinct, unchangeable state. They work well in cases like UI state handling, where each possible state (e.g., loading, success, error) is predefined and must be accounted for.&lt;/p&gt;

&lt;p&gt;Use Sealed Interfaces when you need flexibility and want to share behavior across different types that aren’t necessarily in a strict inheritance hierarchy. Sealed interfaces are ideal for cases where multiple types share behavior but also may combine with other interfaces or classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance and Compatibility Considerations
&lt;/h2&gt;

&lt;p&gt;Since sealed classes and sealed interfaces are both evaluated at compile-time for exhaustiveness, they don’t introduce additional runtime overhead, making them performant. However, it’s worth noting that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sealed Classes&lt;/strong&gt;: Each subclass must be nested or within the same file as the sealed class, limiting their flexibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sealed Interfaces&lt;/strong&gt;: Since they support multiple inheritance, sealed interfaces are more versatile but should be used cautiously to avoid creating overly complex hierarchies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Sealed classes and sealed interfaces both bring powerful type safety and code clarity to Kotlin. By understanding when to use each, you can build more robust, flexible, and readable code structures. Whether you’re representing fixed UI states with sealed classes or creating flexible hierarchies for items in a list with sealed interfaces, Kotlin’s sealed types offer a range of options to support your architecture.&lt;/p&gt;

&lt;p&gt;Choosing the right approach can significantly improve the maintainability and readability of your code, making your Kotlin projects more robust and reliable in the long run.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>programming</category>
      <category>beginners</category>
      <category>basic</category>
    </item>
    <item>
      <title>Mastering runCatching in Kotlin: How to Avoid Coroutine Cancellation Issues</title>
      <dc:creator>Valerii Popov</dc:creator>
      <pubDate>Tue, 29 Oct 2024 12:18:52 +0000</pubDate>
      <link>https://dev.to/inoshishi/mastering-runcatching-in-kotlin-how-to-avoid-coroutine-cancellation-issues-5go2</link>
      <guid>https://dev.to/inoshishi/mastering-runcatching-in-kotlin-how-to-avoid-coroutine-cancellation-issues-5go2</guid>
      <description>&lt;p&gt;The &lt;code&gt;runCatching&lt;/code&gt; function in Kotlin is a powerful tool that lets you handle exceptions within a block of code while preserving the result. However, when working with coroutines, &lt;code&gt;runCatching&lt;/code&gt; can introduce unexpected issues. Because it catches all exceptions, including &lt;code&gt;CancellationException&lt;/code&gt;, it can interfere with proper coroutine cancellation. In this article, we’ll explore how &lt;code&gt;runCatching works&lt;/code&gt;, its potential pitfalls in coroutines, and how to build custom &lt;code&gt;Result&lt;/code&gt; extensions to handle exceptions safely without impacting cancellation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is &lt;code&gt;runCatching&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;runCatching&lt;/code&gt; is a utility function in Kotlin that executes a block of code and wraps the result in a &lt;code&gt;Result&lt;/code&gt; object. If the block completes successfully, it returns a &lt;code&gt;Result&lt;/code&gt; with the value. If an exception occurs, it wraps the exception instead, so you can handle errors more concisely without try-catch blocks.&lt;/p&gt;

&lt;p&gt;Here’s an example of how &lt;code&gt;runCatching&lt;/code&gt; is typically used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val result = runCatching {
    // Some operation that might throw an exception
    performNetworkRequest()
}.onSuccess {
    println("Success: $it")
}.onFailure {
    println("Error: ${it.message}")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pitfall: Catching &lt;code&gt;CancellationException&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In Kotlin, coroutine cancellations are controlled by throwing &lt;code&gt;CancellationException&lt;/code&gt;. When a coroutine is cancelled, it throws this exception up the call stack, which propagates the cancellation signal. However, because &lt;code&gt;runCatching&lt;/code&gt; catches &lt;strong&gt;all&lt;/strong&gt; exceptions, including &lt;code&gt;CancellationException&lt;/code&gt;, it can intercept and handle cancellation attempts unintentionally, preventing the coroutine from being properly cancelled.&lt;/p&gt;

&lt;p&gt;Example of &lt;code&gt;runCatching&lt;/code&gt; Interfering with &lt;code&gt;Cancellation&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Hypothetical Retrofit service with a function that returns a Response&amp;lt;String&amp;gt;
interface ApiService {
    suspend fun fetchDataFromServer(): Response&amp;lt;String&amp;gt;
}

// Function that performs a network call and handles errors using runCatching
suspend fun fetchData(apiService: ApiService): Result&amp;lt;String&amp;gt; {
    return runCatching {
        val response = apiService.fetchDataFromServer()

        // Check if the response is successful
        if (response.isSuccessful) {
            response.body() ?: throw Exception("Empty response body")
        } else {
            throw HttpException(response)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, &lt;code&gt;runCatching&lt;/code&gt; is used to wrap the Retrofit network call. This might look like a concise way to handle errors, but it has an important flaw when dealing with coroutines: &lt;code&gt;runCatching&lt;/code&gt; catches all exceptions, including &lt;code&gt;CancellationException&lt;/code&gt;.&lt;br&gt;
When &lt;code&gt;fetchDataFromServer()&lt;/code&gt; is called in a coroutine and that coroutine is cancelled, &lt;code&gt;CancellationException&lt;/code&gt; is thrown to signal that the coroutine should stop running. However, because &lt;code&gt;runCatching&lt;/code&gt; catches all exceptions indiscriminately, it will catch the &lt;code&gt;CancellationException&lt;/code&gt; along with any other exceptions. This can prevent the coroutine from cancelling correctly, which may lead to unexpected issues such as unresponsive UI or memory leaks.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution: Custom Extension Functions for &lt;code&gt;Result&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;To safely handle exceptions without interfering with coroutine cancellation, we can create custom extensions on &lt;code&gt;Result&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;onFailureOrRethrow&lt;/code&gt;: An extension function that lets you specify an exception type to rethrow, allowing other exceptions to be handled normally.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;onFailureIgnoreCancellation&lt;/code&gt;: An extension that specifically ignores &lt;code&gt;CancellationException&lt;/code&gt;, allowing you to handle other exceptions without blocking coroutine cancellation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s how to implement these extensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inline fun &amp;lt;reified E : Throwable, T&amp;gt; Result&amp;lt;T&amp;gt;.onFailureOrRethrow(action: (Throwable) -&amp;gt; Unit): Result&amp;lt;T&amp;gt; {
    return onFailure { if (it is E) throw it else action(it) }
}

inline fun &amp;lt;T&amp;gt; Result&amp;lt;T&amp;gt;.onFailureIgnoreCancellation(action: (Throwable) -&amp;gt; Unit): Result&amp;lt;T&amp;gt; {
    return onFailureOrRethrow&amp;lt;CancellationException, T&amp;gt;(action)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these extensions, you can handle failures more selectively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val result = runCatching {
    val response = apiService.fetchDataFromServer()
    if (response.isSuccessful) {
        response.body() ?: throw Exception("Empty response body")
    } else {
        throw HttpException(response)
    }
}.onFailureIgnoreCancellation {
    // Handle errors other than CancellationException
    println("Handled non-cancellation error: ${it.message}")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, if a &lt;code&gt;CancellationException&lt;/code&gt; is thrown, it bypasses the failure handler, allowing the coroutine to cancel as intended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;runCatching&lt;/code&gt; in Kotlin simplifies exception handling but requires extra caution in coroutines due to its tendency to catch all exceptions, including &lt;code&gt;CancellationException&lt;/code&gt;. By creating custom extensions like &lt;code&gt;onFailureOrRethrow&lt;/code&gt; and &lt;code&gt;onFailureIgnoreCancellation&lt;/code&gt;, you can ensure that your code handles errors flexibly while respecting coroutine cancellation.&lt;/p&gt;

&lt;p&gt;These extensions provide a safer, more reliable approach to managing errors in coroutines and can be incorporated into your codebase to streamline exception handling in a variety of coroutine contexts.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>basic</category>
      <category>android</category>
      <category>programming</category>
    </item>
    <item>
      <title>Inline Classes in Kotlin: Why, Where, and How to Use Them</title>
      <dc:creator>Valerii Popov</dc:creator>
      <pubDate>Mon, 28 Oct 2024 08:36:10 +0000</pubDate>
      <link>https://dev.to/inoshishi/inline-classes-in-kotlin-why-where-and-how-to-use-them-1cg8</link>
      <guid>https://dev.to/inoshishi/inline-classes-in-kotlin-why-where-and-how-to-use-them-1cg8</guid>
      <description>&lt;p&gt;Inline classes in Kotlin allow you to wrap a single value with a custom type to improve code safety and readability. Unlike regular classes, inline classes do not add runtime overhead since they get "inlined" by the compiler—meaning no actual object is created at runtime. This article explores why and where to use inline classes, how they differ from &lt;code&gt;typealias&lt;/code&gt;, and includes examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Inline Classes?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Type Safety&lt;/strong&gt;: Inline classes help prevent accidental usage of similar data types. For example, a UserId and a ProductId may both be represented as Strings, but they are not interchangeable concepts. Inline classes ensure that they remain distinct types at compile time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Runtime Performance&lt;/strong&gt;: With inline classes, Kotlin removes the need to create wrapper objects by inlining the wrapped value wherever possible. This makes them more efficient for performance that often pass around small values like IDs, codes, or identifiers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Readable Code&lt;/strong&gt;: Inline classes give meaningful names to otherwise generic values, making code more self-explanatory and easier to understand.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Defining an Inline Class
&lt;/h2&gt;

&lt;p&gt;To define an inline class in Kotlin, use the &lt;code&gt;@JvmInline&lt;/code&gt; annotation along with &lt;code&gt;value class&lt;/code&gt;, and ensure it contains only one val property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@JvmInline
value class UserId(val id: String)
@JvmInline
value class ProductId(val id: String)

fun fetchUser(userId: UserId) {
    println("Fetching user with ID: ${userId.id}")
}

fun main() {
    fetchUser(UserId("1")) // OK
    fetchUser(ProductId("1")) // NOT OK. Even though inlined type is String
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, UserId and ProductId are inline classes that wrap &lt;code&gt;String&lt;/code&gt;. Even though they have the same underlying type (&lt;code&gt;String&lt;/code&gt;), Kotlin treats them as distinct types, preventing accidental mix-ups.&lt;/p&gt;

&lt;h2&gt;
  
  
  When and Where to Use Inline Classes
&lt;/h2&gt;

&lt;p&gt;Inline classes are especially useful when you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Wrap Identifiers or Codes&lt;/strong&gt;: When you have unique IDs or codes (e.g., UserId, ProductId) and want to avoid the risk of accidentally swapping them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduce Overhead in High-Frequency Calls&lt;/strong&gt;: For functions or APIs where performance matters, inline classes avoid the cost of additional object creation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encapsulate Domain-Specific Types&lt;/strong&gt;: They’re great for representing domain-specific types, such as currency, weight, or distance, without the need for full-fledged classes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Comparison with &lt;code&gt;typealias&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;typealias&lt;/code&gt; in Kotlin is another way to add meaning to a type without creating a new one. However, unlike inline classes, &lt;code&gt;typealias&lt;/code&gt; only creates an alias without actual type safety at compile time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;typealias UserId = String
typealias ProductId = String

fun printProductId(id: ProductId) {
    println("Product ID: $id")
}

// The following would compile, even though it's an incorrect usage.
val userId: UserId = "user_id"
printProductId(userId) // Will print Product ID: user_id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;typealias&lt;/code&gt;, &lt;code&gt;UserId&lt;/code&gt; and &lt;code&gt;ProductId&lt;/code&gt; are just aliases of &lt;code&gt;String&lt;/code&gt;, so Kotlin treats them as interchangeable, which risks accidental misuse. Inline classes avoid this issue by creating distinct types for &lt;code&gt;UserId&lt;/code&gt; and &lt;code&gt;ProductId&lt;/code&gt; at compile time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Inline classes in Kotlin provide a robust way to add type safety, improve code readability, and optimize performance for lightweight wrappers around values. They are particularly useful for identifiers or small values that would otherwise create unnecessary object allocation. By using inline classes, you get the best of both worlds: compile-time safety without runtime overhead.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>android</category>
      <category>beginners</category>
      <category>java</category>
    </item>
    <item>
      <title>Do We Really Need Use Cases in Mobile Apps?</title>
      <dc:creator>Valerii Popov</dc:creator>
      <pubDate>Sat, 26 Oct 2024 02:20:23 +0000</pubDate>
      <link>https://dev.to/inoshishi/do-we-really-need-use-cases-in-mobile-apps-20k9</link>
      <guid>https://dev.to/inoshishi/do-we-really-need-use-cases-in-mobile-apps-20k9</guid>
      <description>&lt;p&gt;In mobile development, use cases are often used to encapsulate business logic, providing a clear structure for handling interactions between the app’s presentation layer and data layer. However, in many mobile apps, especially those with straightforward data access needs, use cases end up being simple wrappers around repository calls. Let’s explore what use cases are, why they’re commonly used as repository wrappers, and when you might want to consider omitting them altogether.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What is a Use Case?
&lt;/h2&gt;

&lt;p&gt;A use case in software development represents a specific action or task within the application’s business logic. In mobile development, use cases are classes that contain single responsibilities, often designed to perform a single action, like &lt;code&gt;FetchUserProfile&lt;/code&gt; or &lt;code&gt;GetUserPosts&lt;/code&gt;. They serve as intermediaries between the ViewModel (presentation layer) and the repository (data layer), aiming to encapsulate business logic for a single action.&lt;/p&gt;

&lt;p&gt;Here’s an example of a simple use case class in Kotlin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Example Use Case in Kotlin
class FetchUserProfileUseCase(
    private val userRepository: UserRepository
) {
    suspend operator fun invoke(userId: String): User {
        // The use case orchestrates the fetching of user profile data.
        return userRepository.getUserProfile(userId)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structure can be beneficial if there’s complex logic involved in obtaining the User data, like validating the userId or applying filters, caching, or error handling. However, if the use case merely calls the repository function, it might add unnecessary layers to the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Use Cases as Wrappers: Adding an Extra Layer
&lt;/h2&gt;

&lt;p&gt;In many mobile apps, especially those with straightforward data requirements, use cases often end up acting as thin wrappers around repository calls, simply forwarding requests to the repository without additional business logic.&lt;/p&gt;

&lt;p&gt;Here’s an example of a "wrapper" use case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class GetPostsUseCase(private val postRepository: PostRepository) {
    suspend operator fun invoke(): List&amp;lt;Post&amp;gt; {
        // Just calls the repository, without any additional processing.
        return postRepository.getPosts()
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;GetPostsUseCase&lt;/code&gt; doesn’t provide any real value on top of what the repository already does. The repository itself could be directly accessed by the ViewModel, following the Repository Pattern, without sacrificing readability or maintainability. This pattern calls data from a centralized source and could be an ideal way to streamline code.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. When to Consider Omitting Use Cases
&lt;/h2&gt;

&lt;p&gt;In cases where a use case doesn’t add value beyond calling the repository, omitting it can simplify your codebase. Calling the data layer directly via a repository in these situations makes your code easier to read and maintain without sacrificing structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ProfileViewModel(
    private val userRepository: UserRepository
) : ViewModel() {
    fun getUserProfile(userId: String) = liveData {
        emit(userRepository.getUserProfile(userId)) // Directly calling the repository.
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By directly using the &lt;code&gt;UserRepository&lt;/code&gt;, we reduce the need for an extra class and method that serves no additional purpose. For straightforward data access patterns, the repository pattern alone can keep the code well-organized while avoiding the verbosity and potential maintenance of unnecessary use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Streamline Where Possible
&lt;/h2&gt;

&lt;p&gt;While use cases can provide clarity and structure in complex applications with business logic-heavy features, they are often overused as simple data wrappers in mobile apps. In situations where they don’t contribute additional functionality or encapsulate business logic, omitting empty use cases can simplify your code. As always, choose what best fits your app’s needs and keep your code as lean as possible.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Hello World! 👋</title>
      <dc:creator>Valerii Popov</dc:creator>
      <pubDate>Fri, 25 Oct 2024 02:32:11 +0000</pubDate>
      <link>https://dev.to/inoshishi/hello-world-54o7</link>
      <guid>https://dev.to/inoshishi/hello-world-54o7</guid>
      <description>&lt;p&gt;Hello World! 👋&lt;/p&gt;

&lt;p&gt;Hi, I’m Inoshishi, an Android engineer with 7 years of experience building native apps. I take on programming challenges at my own pace, always learning and improving.&lt;/p&gt;

&lt;p&gt;This is actually my first time writing posts, so it’s a new journey for me. I’ll be sharing what I learn, the challenges I face, and how I tackle them. Whether it’s architecting apps or debugging, I hope to offer something useful along the way.&lt;/p&gt;

&lt;p&gt;Let’s enjoy this journey together, one step at a time 🚀&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>androiddev</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
