Lightweight Modularization for an iOS App

Muhammad Muizzsuddin
6 min readNov 17, 2018

--

You write an app. It just a simple app in the first place. As time goes on, you find a lot of useful features that will attract more user and serve the current user well. You find a good pattern to modularize your app and just put a single class in your executable target module. Well designed, but not error-proof. Fortunately, the error rises up on compile times. The bad news is, you have written one thousand lines of code affected by the error. That’s another story.

Here are some of my notes when I am building an app called Muslim App. It was an app which you may find “a lot” of sub-app. Just like Google with its sub-app — Gmail, Docs, etc.

I built Muslim App as a launcher for its sub-app which some of them are Muslim Note (muNote), Muslim Job (muJob), and Muslim Agenda (muAgenda). The goal of the app in developer perspective is pretty straightforward, you build an app which is easy to compose to a bigger app as well as easy to release as a single app.

Let’s put down these requirements into an imaginary storytelling design.

  1. First of all, you need to generalize common components from these sub-apps to be composable into a single app. You declare a protocol in which will be implemented by these sub-apps. The protocol you declare will be ‘SubApplication’.
  2. You implement a design which the Muslim App (will be referenced as ‘Container’) will depend to this protocol to launch its sub-apps.
  3. Finally, you wire up these scattered apps and find your design is at least, clean to be composable. Once you need to add more sub-apps, you implement the protocol and register it to the Container. And you still be able to launch your sub-apps as a single app. If you work with a team, you’ll find the development is easier since you don’t need to depend to others work to test your own.

So, tell me about your implementation, boy!
Ahh, Okay!

Xcodeworkspace is a document that group another document so you can work on them together. This is the first thing you may want to know. And for I am using this workspace approach, then I assume you know it. There are other approaches but I will stick with xcodeworkspace for now.

Documentation is your best friend!

Before move on, it’s always good to remember that the terms used in this article may conflict with your prior understanding. If those conflicts confuse you, please to remember that terms in this article is bound by its context which means current purpose, modularization.

Recall to our requirements, it needs a protocol which serves as a gateway for the Container to start its sub-apps. You make a project which will have two main targets, an executable iOS Single View Application and a CocoaTouch framework. Your project will be named MuslimApp (the Container).

You may want to choose Single View Application on project creation since the name will also be the name of your xcodeproject document.

To create a new target, choose File > New > Target… and select a CocoaTouch framework. Name your new target ‘SubApplication’ like below. You’ll declare your gateway protocol in this target (module).

Yay, you have done the first step to modularize Container and its sub-app gateway. For you may curious, put gateway protocol in a separate target (module) helps you to define a clear structure for your project. And since SubApplication module (will be called Gateway) is lightweight, you have no doubt to import it to a sub-application.

Define the protocol!

Swift employes protocol-oriented programming paradigm which you’ll be wondered how powerful it is. So, let’s declare your Gateway protocol first!

public protocol SubApplication { }

Here you use public since Swift access modifier works based on module scope. Public modifier lets your type to be visible in another module.

The generalized requirement of sub-application in the following list :
1. Name
2. Thumbnail
3. Starter

A name is your application name, Muslim Note etc.
A thumbnail is your application icon, mostly, but you can choose your own.
A starter is just like how the Container to jump to navigate to the sub-application.

For you may ask what the implementation of a starter is, here is the next of your Gateway protocol.

Since iOS application will depend on an UIViewController mechanism for navigating between screens, your starter will be an UIViewController object. You may want to use Navigator pattern, but for now, the implementation of Navigator pattern will be put aside. For the sake of ease to follow!

App Launcher

Since you have a Gateway, you need a ‘consumer’ of it. A Gateway is just like an API that both consumer and producer know.

This figure illustrates the design:

Consumer < Gateway < Producer

Your consumer, Container, will only know that there is an array of object implement the Gateway and Container responsibility is just to use public interface as it wants. The Container doesn’t need to know how to provide a starter, because it has lifted up to Gateway implementer.

Let’s make the code to real.

You provide a controller to display a list of sub-application using AppLauncherViewController. For fast prototyping, a subclass of UITableViewController works best.
You provide Application class to which interact directly with Gateway implementer instantiation. Will be covered next.

Sub-Application Implementation

There are various way to define an implementation of the Gateway. How it can be?

Suppose you use different UI Architecture design foreach sub-application — that’s the benefit of modularization too — you will implement differently in MVC, MVP, VIPER, Rx+MVVM, Redux, etc. You interested with Uber’s Riblet?

But for ease, current implementation will stick to conform Application to SubApplication protocol.

Before we move on, let’s recall on the requirements in matter of SubApplication :

  1. It must be composable to bigger app.
  2. It must be able to release on its own.

Which means, we must design the sub-application to have its own executable target as well as importable module. Interesting!

You start by create new project of your sub-application — Muslim Note — the same way you create for Muslim App. But now, you will make the CocoaTouch framework target named MuslimNote and the executable target named MuslimNoteApp.

Let’s import SubApplication module in MuslimNote module and conforms it for MuslimNote.Application.

Application will responsible for two purposes. Its start(window:) method will be called from MuslimNote.AppDelegate and SubApplication implementation will serves Container — MuslimApp — requirement.

Compose!

Now you have basic skeleton for a modularized app. You have Container, Gateway, and Gateway-Implementer. Your Implementer also capable of running its own executable so if your team wants to add new Implementer, you dont need to build huge application only to see your own Implementer works properly. And you can release your own if needed.

The composition will be in Container Application. Before that, make sure you import MuslimNote into MuslimApp

And to launch it, make use of starter property in AppLaucherViewController

Nice!

Some Consideration

For each bundle based object, you need to instatiate by specifying its bundle. See MuslimNote.HomeController instatiation. You can make helper for ease!

Feel free to put your tought in comment section.

--

--

Responses (1)