GitXplorerGitXplorer
p

RickAndMorty

public
1 stars
2 forks
0 issues

Commits

List of commits on branch main.
Unverified
b947be699fb73e4c3e28aa3348dabc80837118c2

Remove reference to snapshot testing package

ppouyayarandi committed a year ago
Unverified
da7b3fac7a7faa5ff400079c84de0ccdfbbdd04c

Fix flaky tests

ppouyayarandi committed a year ago
Verified
06cb4883715038507dd4eb8e29581e6b9caa0edb

Make xcpretty return same status code as xcodebuild

ppouyayarandi committed a year ago
Verified
f130075b6ecf572d3c83878878b192a2fa67ffe4

Add xcpretty for actions

ppouyayarandi committed a year ago
Verified
cb50150094aab82da675c1109f229e95462f0beb

Create ios.yml

ppouyayarandi committed a year ago
Unverified
93c5120b1b59a3adef2ae4c3e6a190948a9658ef

Improve some tests

ppouyayarandi committed a year ago

README

The README file for this repository.

Rick and Morty app

This project is a sample app for evaluation. In this document you can find the below parts

Architecture

In this project, I have used Clean architecture with the MVVM architectural design pattern. According to the definition of Uncle Bob's Clean architecture, We have these layers in our project:

  • Core (aka Entities): This layer is the lowest one and contains core services (network, etc.), models and interfaces of the higher level (Repositories).
  • Repositories: This layer contains classes that should handle the fetching of data (in our case, it just downloads from the internet, and there is no local database)
  • View Models: In this layer, repositories will be used to handle the logic of every single page in our app. I used Combine for this layer as the binding solution.
  • View Controllers: The highest level layer is ViewController. This layer will bind the data of the previous layer and will be updated with the changes of the observing data.

In this architecture, layers just can be depend on their lower layers and are not able to have any dependency to the upper ones, which makes our code more reusable and less coupled.

Pagination

In both two lists we have in this app, we needed lists to paginate. For this purpose, our repositiories had to have desired methods for pagination. As it was a common behavior and there was a normal structure for that among APIs, I decided to define it as a protocol.

protocol ListRepositoryProtocol: AnyObject {
    associatedtype Response: PageResponse
    
    var network: NetworkProtocol { get }
    var lastPageInfo: PageData? { get set }
    
    var firstPageRequest: NetworkRequestModel { get }
    var nextPageRequest: NetworkRequestModel? { get }
}

extension ListRepositoryProtocol {
    func getFirstPage(completionHandler: CompletionHandler<Result<Response, NetworkError>>?) { ... }
    func getNextPage(completionHandler: CompletionHandler<Result<Response, NetworkError>>?) { ... }
}

This protocol defines the common behavior of paginating services by an extension. For a better vision you can check CharacterRepository and LocationRepository as examples of comformance to this protocol. The rest of the things about pagination have been handled in the view controllers and the view models.

IoC Container

I used Swinject as IoC container in this project. What made me to use it was that if we had lots of dependencies, we needed to inject each one in an initializer, which would make our init() functions bigger and bigger. But with the power of containers, we can pass a container and then, the entity will resolve the needed dependencies from it.

Coordinators

The coordinator pattern has been used for handling the navigations. Although this app has just two pages, but the navigations can getting more complex through the growth of the app. So choosing this approach can help us with development in a more scalable way. Currently, we have three coordinators, one for the first tab, one for the second one and a root coordinator (you can find it as AppCoordinator). Each coordinator passes the containers to the sub coordinators and in the init of them, needed dependencies will be initialized. We could pass containers even for another level to the view models, but at this time I think has no point for us.

Tests

Some test cases has been written for this project. Through this test cases, some parts of app (e.g. network layer, repositories, view models, etc.) has been tested. The coverage of the app is 56% at the moment and is able to increase because tests are just related to the Characters tab and the Location has no test. For CharacterListViewController, I used snapshot testing, which compares the view with a stored snapshot in both of light and dark appearance. Also in all of test cases I tried to mock the external data to reduce the effect of the other services on the tests as much as possible.

To Do

Although I tried to do my best for this project, because of the shortage of time some tasks could be done but at the moment it's not possible. Some of these tasks are:

  • Add some UITest cases: We can add some UITest as E2E or integrated tests in the future.
  • More powerful coordinators: At the moment our coordinators are very basic, but with new requirements they can get developed.