This is a hypothetical take-home assignment. For full problem definition see the issue.
- Sample Android Code Challenge
- Implementation Details
This is an Android application built using Kotlin, Jetpack Compose, and Ktor for networking. The app retrieves a JSON response containing numbers, processes them into structured items with checkboxes, and displays them in a categorized list view.
- Fetches numbers from an API (
https://arjmandi.de/numbers.json). - Handles network failures and malformed responses gracefully.
- Parses each number to determine:
- Section Index (0-3 → SECTION1-SECTION4)
- Item Value (e.g., Item1, Item2, etc.)
- Checkmark Status (Checked/Unchecked)
- Displays parsed numbers in a grouped, sorted list using Jetpack Compose.
- Network Mode Selector: Simulates different network conditions (Stable, Flaky, No Connection, Malformed Response).
- Android Studio Flamingo or newer
- JDK 11+
- Gradle 8+
- Open the project in Android Studio
- Sync Gradle & Run the App
- Select an emulator or a physical device.
- Click
▶️ to run the application.
- The app provides a dropdown menu to select network conditions:
- Stable: Fetches numbers normally.
- Flaky: Simulates timeouts & incomplete responses.
- No Connection: Simulates no network availability.
- Malformed Response: Simulates a broken JSON response.
- Items are categorized under SECTION1-SECTION4 based on the parsed data.
- Checkboxes indicate whether an item is checked or not.
- Click "Get New Numbers" to refresh data.
- Open
ParserTest.ktorNetworkSimulatorTest.ktand run the tests using:./gradlew test - The project contains tests for:
- JSON Parsing (
NumberParserImpl.kt) - Network Simulation (
NetworkSimulator.kt)
- JSON Parsing (
This project is built using Kotlin-first libraries that are lightweight and easy to use, ensuring modern and efficient Android development:
- Retrofit is great, but it's not 2014 anymore. (Sorry Jake Wharton!)
- Unlike Retrofit, Ktor is a Kotlin-native HTTP client designed with coroutines in mind.
- Lightweight and flexible, allowing smooth error handling and response parsing.
- Built-in coroutine support ensures non-blocking network calls.
- Less boilerplate compared to Retrofit.
- A simple, Kotlin-first DI framework without reflection.
- Easier to set up and use compared to Dagger/Hilt.
- Supports modularization without excessive boilerplate code.
- Designed specifically for Kotlin, making mocking easier.
- More intuitive compared to Mockito when dealing with coroutines and extension functions.
- Provides structured concurrency and avoids callback hell.
- Used for network calls, parsing, and UI updates, making the code efficient and readable.
- Works seamlessly with Jetpack Compose and Ktor.
The NumberDataSource module is kept separate for:
- Reusability: This module can be used in other projects, such as a different module in the same app, a backend service or another Android app.
- Scalability: If the parsing logic needs to be changed or extended (e.g., support different APIs), we can do so without affecting the main app.
- Testing: The parsing and network logic can be independently tested without UI dependencies.
The module provides:
- A data repository to manage API and mock data.
- A parser that converts raw JSON numbers into structured data.
- A network simulator to handle different network conditions.
The task required extracting meaningful values from numbers in a JSON array. We implemented the parsing logic using bitwise operations:
Each number (0-255) is processed as follows:
- Extract Section Index → Last 2 bits (
number & 0b11) → DeterminesSECTION1toSECTION4. - Extract Item Value → Bits 2-6 (
(number shr 2) & 0b11111) → Maps toItem1toItem32. - Extract Checkmark Status → Most significant bit (
(number & 0b10000000) != 0) → Determines if the item is checked.
This approach ensures:
- Fast, efficient parsing using bitwise operations.
- Error handling for invalid numbers (out of range or malformed values).
- Scalability (can extend mapping rules if needed).
Since the real API was unavailable, we created a mock network simulator to test different conditions:
- Stable → Returns a normal response with valid numbers.
- Stable with Malformed Response → Randomly includes invalid data (e.g., empty response, string values in JSON).
- Flaky → Simulates timeouts and incomplete responses.
- No Connection → Simulates an offline state by throwing an
IOException.
- Uses a random generator to create realistic failures.
- Can simulate an empty response or corrupted data.
- Injects network delay (
delay(3000)) for timeout scenarios. - Helps test how the app handles errors without needing an actual API.
The project follows a modular, clean architecture, ensuring scalability and maintainability:
App Module (UI + ViewModel)
│
├── numberdatasource (Data Layer)
│ ├── repository (Handles API & mock data)
│ ├── parser (Processes numbers)
│ ├── mock (Simulates network responses)
│ ├── di (Dependency injection using Koin)
- ViewModel requests numbers from
NumberDataSource. NumberDataSourcefetches fromApiClientorNetworkSimulator.- The response is parsed into structured
ParsedNumberobjects. - ViewModel updates the UI state, triggering Jetpack Compose.
This architecture ensures:
- Loose coupling between UI, data, and networking layers.
- Easy unit testing for each component.
- Scalability for adding features (e.g., offline caching with Room).
This project was developed in 10-12 hours, and naturally, some trade-offs had to be made. My guiding principles are:
- "Perfect" is the enemy of "good" – Delivering something functional within constraints is better than endlessly optimizing.
- Make it work, then make it better – Prioritize a working solution before refining it.
- Time is linear and continuous – A solution must fit within the available time.
- Focused testing on core logic: I wrote tests only for
NumberParserandNetworkSimulator, as they are the backbone of the app. Ideally, the UI, repository, and other classes should have tests too. - No NDK implementation (yet): I considered implementing the
NumberDataSourcein C++ with NDK, but refreshing my knowledge on JNI would take time. However, the current design allows easy reuse in a JVM backend environment. - Long
NumberListScreen.ktfile: The composables inside it could be moved into separate files for better modularity. It's not terrible, but it could be improved. - More abstraction would improve maintainability: Given more time, I would add even more abstraction layers to keep the codebase even cleaner.
- ViewModel dependency concerns: In my own projects, I never make a direct call to another class from a ViewModel. This anti-pattern makes refactoring and testing harder. Instead, I'd introduce a
NumberContextorNumberMiddlewareclass that acts as a delegate between the ViewModel and data sources. A similar approach would also apply toNumberDataSourceandNetworkSimulator, keeping dependencies more manageable.
This implementation prioritizes modularity, efficiency, and testability. By leveraging Kotlin-first libraries, bitwise operations for parsing, and network simulation, we ensure a robust and maintainable Android solution. Trade-offs were made to deliver the best possible result within the given time constraints while keeping future improvements in mind.
📧 Contact: javad@arjmandi.de