Provide the needed infrastructure to build clean Domain-Driven Design (DDD) apps in the Java ecosystem
Explore the docs »
Report Bug
·
Request Feature
Radix is a lightweight Kotlin framework that provides a blueprint to build clean, easy-to-maintain, and highly-scalable server-side components. It emphasizes on the idea of isolating the bussiness logic of the app from 3rd party dependencies (e.g. Spring) by keeping all core business logic in the usecases layer which makes it easy to expose different kind of services and even port the app into a different framework.
Add the below dependency to the project's dependency management:
<dependency>
<groupId>io.arkitik.radix</groupId>
<artifactId>radix-dependencies</artifactId>
<version>v1.6.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
- JDK version >= 1.8
Let's build a simple User
domain! To do so, we should start with the abstraction from the identity level and then move
to the implementation.
The identity in simple terms is the abstraction of the entity, it extends Identity<ID : Serializable> and specifies the value of the generic type ID.
interface User : Identity<String> {
override val uuid: String
val username: String
val password: String
}
→ it's available through the below dependency:
<dependency>
<groupId>io.arkitik.radix</groupId>
<artifactId>radix-development-identity</artifactId>
</dependency>
The store is similar to the Data Access Object (DAO) pattern, it allows us to isolate the business layer from the persistence layer which means you can swap different persistence layers or change the implementation without affecting the core bussiness of the app! Aside from that, it also provides builders to create/update the entity.
To create our own UserStore
we should extend from Store<ID : Serializable, I : Identity<ID>>
interface UserStore : Store<String, UserIdentity> {
override fun UserIdentity.save(): UserIdentity
override val storeQuery: StoreQuery<String, UserIdentity>
override fun identityCreator(): StoreIdentityCreator<String, UserIdentity>
override fun UserIdentity.identityUpdater(): StoreIdentityUpdater<String, UserIdentity>
}
→ it's available through the below dependency:
<dependency>
<groupId>io.arkitik.radix</groupId>
<artifactId>radix-development-store</artifactId>
</dependency>
The usecase factory allows the consumer to create usecase objects without having to know the details about their implementation, dependencies, or how they get created.
As a consumer, all you need to know is the signature of the usecase which is basically:
- What does the usecase do (interpreted from the usecase name).
- The usecase request.
- The usecase response.
Let's create our own UserUsecaseFactory
and add findUserByUuidUseCase
usecase to it:
interface UserUseCaseFactory : UseCaseFactory {
val findUserByUuidUseCase: FunctionalUseCase<FindUserRequest, FindUserResponse>
}
and the request/response as follows:
data class FindUserRequest(val uuid: String) : UseCaseRequest
data class FindUserResponse(val identity: UserIdentity?) : UseCaseResponse
→ it's available through the below dependency:
<dependency>
<groupId>io.arkitik.radix</groupId>
<artifactId>radix-development-usecase</artifactId>
</dependency>
The usecase layer is the brains of the app, the core business logic that your app needs to run and is defined through contract abstraction in the usecase-factory.
In our case, we have only one factory with one usecase which is findUserByUuidUseCase
, to implement it we have to
inject the StoreQuery
available from the UserStore
.
class FindUserByUuidUseCase(
private val storeQuery: StoreQuery<String, UserIdentity>,
) : FunctionalUseCase<FindUserRequest, FindUserResponse> {
override fun FindUserRequest.process() = FindUserResponse(storeQuery.find(uuid))
}
and finally the usecase-factory implementation:
class UserUseCaseFactoryImpl(
userStore: UserStore,
) : BankUseCaseFactory {
override val findUserByUuidUseCase = FindUserByUuidUseCase(userStore.storeQuery)
}
Of course, don't forget to provide the implementation for the identity (i.e. entity) and the store (i.e. adapter). For more examples, please refer to the Documentation.
- Complete the Documentation files
- Business Layer
- Implementation Layer
- Application Layer
See the open issues for a full list of proposed features (and known issues).
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Distributed under the Apache License 2.0. See LICENSE for more information.
Ibrahim Al-Tamimi - ibm.iloom@gmail.com
Project Link: https://github.com/arkitik/radix