Rethinking Networking in Android
Turning Android repositories into composable effects
1Problems with the Traditional Repository Model
In Android applications, operations like fetching user information, creating posts, uploading files, and sending notifications are often implemented through a series of repository calls, temporary variables, and nested try/catch blocks. Repositories typically remain as wrappers around Retrofit or Room objects, hiding the implementation details of the underlying data source.
2Computation Model Instead of Repository
A repository can be thought of not as a place where data comes from but as a computation that produces data, propagates errors, and can be composed with future network operations. This approach replaces methods like getUser() or createPost() with a computation that can be transformed, chained, and executed only when needed.
3Mathematical Concept of Computation
In mathematics, a computation can be considered a process that consumes some input, performs a series of transformations, and eventually produces either a value or an error. In this process, how the work is performed is often less important than the objects participating in the computation and the rules governing their interaction.
4Fundamental Objects in Networking
In a typical networking workflow, three fundamental objects emerge: a value that may succeed or fail, a set of operations the backend can perform, and a mechanism for translating transport-specific data into domain concepts. These objects form the foundation upon which the rest of the architecture is built.
5Values and Errors
Every network request has two possible outcomes: it either succeeds and produces data or fails and produces an error. These possibilities can be modeled explicitly using a Result type, which indicates that a computation may produce a User or a NetworkError, providing a predictable structure that can be transformed and composed.
6Capabilities Instead of Endpoints
Traditional networking layers often expose a large collection of service methods. However, this architecture models the backend in terms of capabilities, defining the environment in which a computation can execute. A computation requiring a Get capability can perform read operations, while one requiring a Post capability can perform write operations.
7Domain Concepts Over Transport Objects
The final building block is the distinction between transport data and business data. Network responses are often shaped by the backend to satisfy an API contract, not to model the business domain. Therefore, the architecture separates DTOs from domain models.
8Advantages of Composable Operations
Composable operations allow complex networking workflows to be expressed as a single composable pipeline. This approach eliminates much of the boilerplate surrounding orchestration, centralizes concerns like retries and error handling, and makes networking code read more like a description of a workflow than a sequence of imperative steps.
9Benefits of the Result Type
The Result type explicitly indicates that a computation may succeed or fail, providing a structure that can be transformed and composed. This approach integrates failure into the type system itself, reducing the need for scattered try/catch blocks throughout the application.
10Flexibility of Capabilities
Capabilities define the environment in which a computation can execute, and the computation does not need to know whether these capabilities are implemented using Retrofit, Ktor, or a test double. It only needs to know that the capability exists.
11Importance of Domain Models
Domain models, separated from transport data, better represent the business domain. This distinction allows network responses to model the business domain rather than merely satisfying an API contract, making the architecture more robust.
12Conclusion and Recommendations
This approach makes networking in Android applications more modular and readable. By thinking of repositories as computations, developers can reduce code complexity and express workflows more clearly. This architecture is particularly recommended for applications requiring complex networking operations.
Original article: ProAndroidDev - Medium — Android'de Ağ İşlemlerini Yeniden Düşünmek