Sytac

Sytac iOS assignment | Movies

The time has come for us to unveil the code challenge Sytac has prepared for you. The challenge involves working with the Movies application and includes the following tasks:

Questions

  1. Provide a high-level review of the application. Give your opinion on both aspects you consider positive and aspects you consider negative. Describe how and why would you do things differently. 

  2. The logic of ImageCache hides an issue. Try to discover and fix it.
  3. Replace the binding between Repository and View model without combine.
  4. Replace the Popular detail view with a new custom detail view. This view should display a detail with the info of the model movie model. Please use SwiftUI for the detailed view.
  5. Replace the TopRated tab with a new list view. This view should display a list of the TopRated movies and it must be implemented programmatically using UIKit.
  6. Write unit tests whereever you need them.
  7. In MoviewRow.swift line 11 we use @StateObject, could we change it with @ObservableObject? what are the differences?
  8. In PopularMoviesListViewModel.swift we ask for popular movies, using the current implementation fetch top rated movies instead, and explain what is happening.
  9. Implement load more functionality for Popular movies list screen.

You have total freedom to modify the codebase, there are no constraints on the design/layout of the TopRated screen. The TopRated List and detail view should be created programmatically only (no Interface Builder nor SwiftUI).

Notes: The Movies project works with Xcode 12 and up and the language used is Swift.

Backend:

To retrieve movies related data, the application is using this API
https://www.themoviedb.org/documentation/api

Requisites:

  • The project has to compile without errors.
  • The code should be clean, efficient and understandable. Remember to
    structure your source code correctly (using a nice architecture would
    make this easier).
  • Keep in mind the performance of the application.
  • Use version control in the project to show your progress, commit like you
    would normally.
  • We would like to see at least the first 5 questions solved, the more you provide the better.

Good luck!

License

MIT
Free Software!

Paulo’s Test

Architecture

The app uses MVVM architecture to define its separation of concerns.
SwiftUI and Combine are used to bind UI elements and interactions in the popular tab.
In overall classes are small and encapsulated, which make the app scalable.
For dependency management, Swift Package Manager is the tool of choice.

As for suggestions:

  1. Include a new protocol for viewModel that will define Input and Output objects, which make communication between view and viewModel clearer.
  2. Change the way view communicates with viewModel, for example line 32 on MoviewRow, .onAppear(perform: { movie.fetchImage() }). A view should not initialize a function inside viewModel but instead inform that an action was performed, e.g: .onAppear(perform: { movie.input.onAppear() }). In the future if a viewModel needs to be updated or add more functionalities to a specific action, the view does not need to change, instead just reflect the viewModel state.
  3. Some classes have difficult or unclear naming, e.g: MovieAdaptor, PopularMovie; Unless you open the class and read it, you won’t know what they do so I would suggest adding a few prefixes/suffixes to these files PopularMovieAdapter PopularMovieViewModel`
  4. Folder structure could be improved by adding a few layers for each feature, e.g: View/Popular/Row; Bundling model, viewModel and view in the same folder for a specific feature.

ImageCache Logic

Problem: 
Images not loading when multiple requests are from the same URL

How to reproduce:
Add in line 32 this code let newUrl = NSURL(string: "https://image.tmdb.org/t/p/w500/jKuDyqx7jrjiR9cDzB5pxzhJAdv.jpg”)!
Replace all url variable uses to newUrl, no images will load until you scroll the tableView and cells start requesting from cache instead of needing download.

Fix 1 (Not good but quick):
Line 42 and 67 have a return to stop the function.
Line 42 avoids same url requests to be executed in succession.
Line 67 avoids blocks of the same url to be called, preventing updates to UI.

Commenting both lines, will provide a quick fix to give us time for a proper investigation if issue is critical and needs redeployment. But it may cost more bandwidth and phone memory by updating the views many times.

Fix 2 (Better):

  1. Add more control flows to NSCache with lock
  2. Make use of Quality of Service = Utility on our NSThread to provide a better performance.
  3. Perhaps use Core Data to provide a longer term Cache for users

Replace binding Repository and View model without combine

I’ve added a class called Binder which uses a technique called Boxing, making it easy to drop in and does not require complex changes to the project such as adding RxSwift.

Replace Popular Detail

I’ve added a new design for the detail page, including more data then the popular list.

Replace TopRated Tab

I’ve added a new design for the list page, using entirely UIKit.

Unit Tests

No tests added

MovieRow @StateObject vs @ObservableObject

Yes, in this case it is possible to change @StateObject to @ObservableObject. The main reason is that MoviewRow does not own the instance of PopularMovie and needs to only observe the object.
A good class to understand their differences are in this class from WWDC: https://developer.apple.com/videos/play/wwdc2020/10040/

Fetch Top Rated

To enable Top Rated fetching, we can switch line 25 of PopularMoviesListViewModel.swift from moviesRepo.getPopular() to moviesRepo.getTopRated(). This function will instantiate TopRatedMoviesService instead of PopularMoviesService, this means we will call a different API, on a different path compared to PopularMoviesService, resulting in a a different service response, in this case, IMDB’s Top Rated movies.

Load More for popular movies

Not provided.

GitHub

View Github