Weather in Paris in a blink ! Hourly detail for the current day, by segment on the next 7 days. There is more ! You will discover :
- temperature in celsius
- wind direction
- blowing power
Say bye to bad surprises when leaving the subway (or riding your bike).
Ktlint via kotlinter.
- for packages' names I use camel case (not best practice, I wont do it on next projects).
- for functions arguments, the default is positional. Indeed Android Studio gives enough intel on arguments. I use named arguments only for disambiguation, when optional arguments are in the function's signature. The exception is for Composable functions, where named arguments are mandatory.
- for abbreviations, I use capitalize case, not screaming case. Eg : Dto, not DTO
- tests files (unit and e2e) use
Test
in their names : as a prefix for stubs and as suffix for tests classes - to avoid conflicts with Compose classes, I use the
Main
prefix (e.gMainNavHost
) - for enum classes, I use capitalize case, not screaming case
In version catalog, variables naming is inspired by Now In Android
Google app. Variables' names format depend on type :
[versions]
: camelcase, the shorter the better, egagp
,ksp
. Sometimes prefixing can be necessary, egandroidxEspresso
[libraries]
: kebabcase, merge groupId segments with nameId ones. Eg{ group = "androidx.compose.material3", name = "material3" }
becomesandroidx-compose-material3
. If groupId's segments give no information, they should be discarded, eg{ group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt" }
becomeshilt-android-testing
. Examples of segments with low semantics :com
,google
,io
,dagger
,jetbrains
[plugins]
: kebabcase, based on the groupId, the shorter the better, egksp
,hilt
. Same names than in[versions]
can be used. Prefix can be used for disambiguation, egandroid-application
Weather data for Paris is retrieved from OpenWeather.
API is autogenerated with OpenAPI generator, with all the configuration
and template in weather
subproject, under /open_weather_api
.
The OpenWeather.yaml
file is created by transforming a Postman collection containing an OpenWeather
JSON response to an OpenAPI scheme. This, thanks to this tool.
Once the proper scheme is created, in order to generate the API, simply run :
./gradlew openApiGenerate
Note : The generated DTO fields are all nullable. Instead of a painful configuration of OpenAPI's templates, I've choose to use the not null assertion operator in
WeatherAssembler
.
- Compose Navigation
- Hilt for DI
- Retrofit for network requests
- Ktlint for linting, runs on pre-push
- Kover for code coverage runs on Bitrise (release flavor)
- Compose Preview Screenshot Testing, for
weekly-weather-ui
component. Run :
./gradlew :weekly-weather-ui:validateScreenshotTest
Based on Robert C. Martin's Clean Architecture, more precisely the package by components packaging strategy, proposed by Simon Brown in chapter 24.
The architecture diagram is components_architecture.drawio
file, at the root of this project.
This file has to be open with DrawIO tool (free and really cool).
Separation between abstraction and concrete implementation (especially for remote data sources) is handled via Hilt Modules bindings.
Specific concepts of Repository, Gateway, DTO & Assembler are extract from Eric Evans & Martin Fowler books Domain Driven Design & PEAA.
Data flows contain Kotlin's Result
, which are created on the lowest level (in architectural term), ie
in the network layer implementation. This in order to wrap exceptions as soon as possible, as recommended
in this Kotlin Conf talk.
All the following components are packaged as gradle subprojects.
They strictly follows encapsulation and dependency rule, using interfaces
to define contracts (and for DIP, when needed).
Libraries are encapsulated using internal
modifier.
They are under the com.tibo47.weatherPaname
package.
This component is at the lower level in the architecture. It bootstrap the main activity & application. It connects ui component (see bellow) via navigation. Its android test target provides e2e tests.
This component is an android library. It contains all the business and data-providing logic to retrieve and expose data about Paris' weather. It only exposes OpenWeather Retrofit API & uses cases.
This component is an android library. It contains ui components to display the main screen for the current weather.
Under com.tibo47.httpClient
package.
Exposes a Retrofit factory with :
- KotlinX serialization Json
- HttpLoggingInterceptor
Under com.tibo47.androidPlatform
package.
It contains a preconfigured material design 3 theme and generic, non business oriented, ui components.