9 years ago

Modularize your mobile projects

When we start building mobile apps we tend to do everything on the same bundle. If you are an iOS developer that means only one target, with one scheme with the build config and that project has some dependencies that might be attached as frameworks, static libraries, or using a dependency manager like CocoaPods. If you are familiar with Android you probably use a module with some dependencies managed by Gradle.

If you think a bit about that solution it’s mixing in the same bundle stuff which is strictly related to the device and the presentation layer, the application core logic, and the interaction with the system/external frameworks. What happens if Apple/Google change any of the existing frameworks? You’ll have to analyze your app find all the framework dependencies and replace them and what about using your application core logic in a different device with a different interface? You’ll probably end up adding a bunch of if/else statements in your code. You know that’s not a clean way to do the things…

Both iOS and Android development tools offer great tools to deal with that. However we only use them to link our big app bundle with other dependencies (aka libraries). But.. what if we structure our app in small components which instead of packaging the whole app logic they have a components with the same responsibility grouped. We could easily interchange them easily without having to refactor all the app.

If you are thinking in how to apply those terms to existing architectures like might be MVC, MVP, or VIPER an app structured in bundles separates those architecture components in different modules.

Advantages of working with bundles

The image below shows the difference between working with only a big app bundle and splitting it in small bundles.

Large project

Components

Thinking about the components of our apps most of them can be grouped in the following sacks:

Modules on iOS

Although you can create your own library projects with XCode and create the dependencies manually, we have a great tool you probably know, Cocoapods you probably know about. We usually use it to connect our project with remote dependencies but it has the option to specify the dependency locally. Let’s see how.

You have different approaches depending on your needs. The first one consists on managing those Core/Data bundles as libraries and then connecting your app bundle using the remote repositories. That’s great if you have different teams working each one on a different “library” because they can keep their own versioning and build/deploy processes. If you have an small team and don’t have enough resources to have separated build/deploy processes for each bundle you can have those bundles locally (using Gitmodule) but integrated with CocoaPods as well. That way you have flexibility to modify and report changes directly

Pod::Spec.new do |spec|
  spec.name         = 'ExampleCore'
  spec.version      = '0.0.1'
  spec.homepage     = 'https://github.com/Example/ExampleCore'
  spec.authors      = { 'pepi' => 'pedropb@hey.com' }
  spec.summary      = 'Core logic of example'
  spec.source       = { :git => 'https://github.com/Example/ExampleCore.git', :tag => '0.0.1' }
  spec.source_files = './**/*.{h,m}'
  spec.framework    = ''
end
*Note: In case of ExampleData you might have dependencies with system frameworks or external libraries. You can specify them in the podspec as well*
git submodule add https://github.com/Example/ExampleCore dependencies/core
git submodule add https://github.com/Example/ExampleCore dependencies/data
source 'https://github.com/CocoaPods/Specs.git'
inhibit_all_warnings!
pod 'ExampleData', :path => './dependencies/data'
pod 'ExampleCore', :path => './dependencies/core'

Keep in mind

If you have never developed a library before there’re some points you should keep in mind working with your bundles:

CocoaPods is just a simple way to manage dependencies which in my opinion makes it easier and cleaner. If you have enough experience working with libraries/frameworks and connecting dependencies into a single project feel free to do it that way, any dependency solution is possible.

Modules on Android

In case of Andorid we’ll use Gradle to define our modules. Gradle allows you to specify in your app build file the dependencies the project has with other library-projects. We usually use that feature to link our project with 3rd party libraries but we can do it with other modules created by ourselves. Let’s see how

Library Projects list

Dependencies

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile project(':core')
    compile project(':data')
}

Keep in mind

Before working with Android modules in your projects there are some points I would like to highlight:

Git Submodules and versions

We’ve seen how to use modules in either iOS or Android and how to use Git Submodule to have a local git copy of those “library” modules but what if we want to have an specific branch of the core/data package? Submodules has support for it. If you edit your .gitmodules you’ll have a structure similar to this one where you can specify the branch

[submodule "ExampleCore"]
    path = core
    url = https://github.com/Example/ExampleApp.git
    branch = new-feature

Git Submodules has no support to specify a tag instead of a branch. You can manually checkout to any tag in those submodule repositories.

Documentation

Thoughts

Feel free to contact me on pedropb@hey.com. I’ll be please to comment that project organization with you

About Pedro Piñera

I created XcodeProj and Tuist, and co-founded Tuist Cloud. My work is trusted by companies like Adidas, American Express, and Etsy. I enjoy building delightful tools for developers and open-source communities.