The Kotlin Composable Architecture is a companion library for the amazing Swift Composable Architecture created by Point-Free. This implementation tries to mimic the original version's patterns and techniques, but because Swift and Kotlin have some fundamental differences, there are a few alternative design decisions. Eventually, we are aiming to provide the same ergonomics as the Swift implementation and full feature parity.
Until there is no stable release available, the easiest way to integrate the library into your project is to use Gradle's includeBuild()
feature.
// in build.gradle.kts
implementation("composable-architecture:composable-architecture:0.1.0")
// in settings.gradle.kts
includeBuild("<PATH TO kotlin-composable-architecture>") {
dependencySubstitution {
substitute(module("composable-architecture:composable-architecture"))
.with(project(":composable-architecture"))
}
}
This library provides a few core tools that can be used to build applications of varying purpose and complexity. It provides compelling stories that you can follow to solve many problems you encounter day-to-day when building applications, such as:
-
State management
How to manage the state of your application using simple value types, and share state across many screens so that mutations in one screen can be immediately observed in another screen. -
Composition
How to break down large features into smaller components that can be extracted to their own, isolated modules and be easily glued back together to form the feature. -
Side effects
How to let certain parts of the application talk to the outside world in the most testable and understandable way possible. -
Testing
How to not only test a feature built in the architecture, but also write integration tests for features that have been composed of many parts, and write end-to-end tests to understand how side effects influence your application. This allows you to make strong guarantees that your business logic is running in the way you expect. -
Ergonomics
How to accomplish all of the above in a simple API with as few concepts and moving parts as possible.
For now, the JVM doesn't have the concept of value types (this might change in the future with Project Valhalla). Thus, we cannot provide the reducer a mutable state safely, so it is required to return new copies of the state in case of any mutation. Kotlin's data class
feature comes handy, as a .copy()
methods get generated with named arguments for all properties.
In Kotlin, enums cannot function as algebraic data types. We get to define a single type wrapped inside an enum, but each case cannot have an individual associated type. Instead, we can model actions with sealed class
hierarchies.
The Swift compiler has a powerful feature: it generates KeyPath
s for each struct in our application. Point-Free has implemented a companion library called swift-case-paths, which provides the same ergonomics for enums. The Swift Composable Architecture uses these two tools to abstract over getters and setters for state and action. In Kotlin, we don't have similar tools, so we rely on code generation through the Arrow Meta library. Arrow has a module called Optics, which can be utilized to define Lens
es and Prism
s to substitute KeyPath
s and CasePath
s.
The Swift Composable Architecture is powered by Combine, which comes bundled with iOS SDK 13. The Kotlin Composable Architecture is relying on the Kotlinx Coroutines library. Stores are powered by MutableStateFlow
, and effects are wrappers for coroutine Flow
s.
For more information please visit the Swift Composable Architecture repository.
This library is released under the MIT license. See LICENSE for details.