This is a demo app digesting the iOS Lead Essentials program at the Essential Developer Academy.
The app presents the feed of Studio Ghibli films. The app caches the feed so that the user could enjoy the feed regardless of the connectivity, and images, to prevent excessive bandwidth usage.
Under the hood, it is a project with hyper-modular architecture with decoupled components, with modularity enforced by placing modules into separate targets in the EssentialGhibli
Swift Package.
Open the App/EssentialGhibli.xcodeproj
with Xcode 14.x and select the EssentialGhibli
scheme to run the app on the simulator.
The hyper-modular
architecture allows to develop, maintain, extend, replace, reuse, and test the components in isolation. It simplifies composition, deployment, and team-wide communication via a light-weight Preview App (isolated module-specific apps). It follows SOLID principles
and Dependency Injection
patterns.
with decoupled components
Modules dependency done right significantly reduces build time. This project is definitely not huge, but it's clear that this approach allows utilizing Xcode parallel build system:
The Root Composition
is implemented in the EssentialGhibliApp
: UIComposer
is responsible for the UI, and LoaderComposer
glues together API
and Cache
and manages async behavior (Cache is sync) using Combine.
Presentation
is a platform-agnostic module that defines abstract ResourceState
: loading, loaded, and loading error, for generic Resource
and StateError
.
There are three concrete modules: DetailFeature
, ListFeature
, RowFeature
, and one generic GenericResourceView
, that renders three states of any abstract resource: loading, loaded, and loading error.
UI Components are implemented with SwiftUI
. Previews are designed to show the rendering of different states - loading, loaded, load error - and are covered with snapshot tests - see Tests.
API
has three modules: reusable app-agnostic interface SharedAPI
and its URLSession
implementation in SharedAPIInfra
, and API
itself - the app-specific endpoint and mapper.
Tests cover API
and SharedAPIInfra
with URLProtocolStub: URLProtocol
.
Cache
module implements generic FeedCache
and defines FeedStore
- the interface for the infrastructure, which is implemented with CoreData in CacheInfra
.
Tests cover both modules, separating by uses cases, and extensively using DSL to facilitate testing and decouple tests from implementation details.
Extensive use of TDD
and test DSL
to decouple tests from the implementation details.
UI Components are tested using snapshots with SnapshotTesting. This testing covers light/dark modes and localization.
Flaky and unreliable UI Tests are not used.
English and Russian localizations are tested, in the app module and in UI modules.
SwiftUI supports Dark mode and Dynamic type out of the box, so the app do as well.
For the demo, a simple CI
with GitHub actions
workflow is used: build and run all tests with scheme CI_iOS
run on push to the main
branch. Another workflow with the same functionality could be triggered manually. Both YAML
scripts call clean_build_test.sh
shell script.