Skip to content

matiastripode/instagramclone

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

16 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Instagram Clone

Build Status

iOS Mobile Architecture at scale.

Context

This project mimic an enterprise-size mobile application, where several teams with dozens (and sometimes hundred) of developers contribute to a single application modularized in frameworks. Most likely a single feature team will be responsible of a single feature or closely related features (e.g: Login, Registration and even Profile could belong a single team). In a real world project all features frameworks will have their own repo, same for CommonUI and CommonInfra. Usually later one will land on a mobile platform team responsibility. At first glance the architecture could seem an overkill, but having in mind the scenario described above you can imaging that a monolith application could fairly quickly hit a wall. Making maintainability and adding more feature (or supporting multi-apps) very challenging and in some cases a re-write will be required.

To get some perspective how big and complex a mobile application for big scale is, please consider reviewing next two open-source frameworks developed by Twitter Twitter Network Layer iOS framework and Twitter Image Pipeline iOS framework.

Other challenges face in mobile applications at scale are security, compliance (GDPR, HIPAA, COPA, etc). If payment methods are supported across several countries, then different regulations will take place.

Table of content

Architecture

Each feature follows the same engineering principles and structure (Presentation and Data). All of them uses two common frameworks (CommonUI and CommonInfra).

Challenges due to nature of big scale mobile apps

Building Mobile Apps at Scale: 39 Engineering Challenges

Common challenges:

  1. Polling vs pushing content from/to remote servers. (polling at specific frequency could cause performance issues. It is better for the server to let the app knows when new content should be pull or leverage a third party solution like Firebase or Realm).
  2. Properly manage Feature flags (especially flags that depends on more than one team/feature, that interdependency could create some challenges)
  3. Offline support (what users can do with your app without connectivity?).

Reference

πŸ“‚ : Folder containing source files and/or resources
βš™οΈ : Framework

Application

Folder structure

Screens

Login

Registration

Main πŸ“‚

It contains application specific classes (AppDelegate, SceneDelegate, Main Entry Controller, DI Factories)

Files πŸ“‚

It contains application specific resources (images, Localizable, Info.plist)

Features πŸ“‚

Login βš™οΈ

  1. Presentation πŸ“‚
  1. Models πŸ“‚
  2. Presenters πŸ“‚
  3. Controllers πŸ“‚
  1. Data πŸ“‚
  1. AuthenticationπŸ“‚

Registration βš™οΈ

Feed βš™οΈ

Profile βš™οΈ

ImageSelector βš™οΈ

Search βš™οΈ

Notification βš™οΈ

CommonUI βš™οΈ

Fields Validation πŸ“‚

The main class is ValidationComposite, which uses Composite pattern to easily extend functionality and without actually modifying it (Open-Closed principle)

UI Components πŸ“‚

UIKit Extensions πŸ“‚

UIView+Extensions contains Auto-layout convenience methods

Views πŸ“‚

With WeakVarProxy class it is possible to bind a ViewController with its Presenter without the need of both to know each other: ** WeakVarProxy**

public final class WeakVarProxy<T: AnyObject> {
    private weak var instance: T?

    public init(_ instance: T) {
        self.instance = instance
    }
}

extension WeakVarProxy: AlertView where T: AlertView {
    public func showMessage(viewModel: AlertViewModel) {
        instance?.showMessage(viewModel: viewModel)
    }
}

extension WeakVarProxy: LoadingView where T: LoadingView {
    public func display(viewModel: LoadingViewModel) {
        instance?.display(viewModel: viewModel)
    }
}

Usage

  1. Binding LoginController with LoginPresenter
    let controller = LoginController()
    let presenter = LoginPresenter(alertView: WeakVarProxy(controller), loadingView:  WeakVarProxy(controller))
    controller.login = presenter.login
  1. LoginController
extension LoginController: LoadingView {
    public func display(viewModel: LoadingViewModel) {
        //TODO: Implement
    }
}

extension LoginController: AlertView {
    public func showMessage(viewModel: AlertViewModel) {
        //TODO: Implement
    }
}
  1. LoginPresenter
    init(alertView: AlertView, loadingView: LoadingView) {}
    
    func login(request: LoginRequest) {
        ...
        alertView.showMessage(viewModel: AlertViewModel(title: "Validation Failed",
                                                    message: message))
        ...
        loadingView.display(viewModel: LoadingViewModel(isLoading: true))
        ...
        loadingView.display(viewModel: LoadingViewModel(isLoading: false))
    }

CommonInfra βš™οΈ

Due to its complexity, storage could be part of a separate Storage framework. For sake of simplicity it will be kept in CommonInfra.

HttpClient πŸ“‚

Analytics πŸ“‚

FeatureToggles πŸ“‚

Logging πŸ“‚

SecureStorage πŸ“‚

MemoryStorage πŸ“‚

PersistentStorage πŸ“‚

Roadmap

This project will continue evolving as I add more code

References

Author

Matias Tripode profile

Links

License

Distributed under the MIT License. See LICENSE for more information.

About

No description or website provided.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors