Modular Project Structure with Swift Package Manager (SPM)

Santosh Botre
6 min readAug 27, 2021

--

shutterstock

Every application consists of a couple of features. The application is composed of separate features that can be connected.

Let’s start with a minimalistic set of features.

Functional Features

In addition to these features, it also has supporting components like Network, Database, Logger, etc.

Additional Features To Support Functional Features

As a technical person, be it developer, or software engineer, we all think this in terms of Source Code.

# A project that has lots of files.

Every feature has been achieved with the help of a ton of code files, and feature code is communicating with other feature code.

Each of the features will have some or all kind of code files as, Storyboard, View Controller, View Model, Presenter, Model, Requester/Responder and many more based on our knowlege, choice of the architecture design pattern and the additional requirement the respective feature has.

The feature will be communicating with Network and Database. It will be using utilities like Logger, Analytics, etc.

Hope, we all are good with this set of features and high-level component identification.

# Let’s create a skeleton of the identified features, components, and high-level files that will help us to implement.

Everything grouped properly yet in one project.

The overall project structure is as in the above-depicted picture. It looks neat and clean. However, there’s scope for improvement by having segregation of UI, Domain/Use cases, Business Logic, etc., files.

We all have heard the word called Monolithic. If now above picture is the best example of Monolithic.

What it means?

In this context, Monolithic is the traditional unified model for the design of a software program, which means composed all in one piece.

# This is understood by most of us in the backend world and not in Mobile application development.

We will not discuss the Monolithic pros or cons from loose coupling, maintainability, performance, build time, etc. We will try to keep it simple.

## Few observations are based on the structure of the project.

  1. Only one target with the app source.
  2. Only one Storyboard by Design. (NOTE: We can have multiple)
  3. Only one Test Target by Design.
  4. As time passes, maintaining the project structure is cumbersome. In short, no one gone follow it.

How to overcome the problems by design?

Modular structure of iOS applications to enable self-governing, sovereign, scalability, optimize the build and independent test cycles, and ensure good practices in our project.

The core idea is to build the project by building independent features that are interconnected using clear and concise APIs use Protocol Oriented Programming.

What do we have to do?

  • Know the autonomous features
  • Know the vertical layers
  • Know the common checkpoint
  • Know integrated and aggregated systems

Why Modular Architecture?

  • The monolithic project is Hardstone.
  • Brings frustration when we are asked to work on those projects.
  • The project tends to grow in size (large codebase/large team) as the day passes.
  • It turns complex, tough to manage, hard to manage by resources.
  • Divide and conquer
  • Small modules
  • Reusability

“Modularising an project consists on organising an source code and resources in multiple modules”

The beauty of modular architecture is that we can replace or add any one component (module) without affecting the rest of the system.

The modular architecture will support the scalability of large XCode codebases. To make, manage, build, maintain we need platform support, support of tools, and IDE support.

Modular architecture using Swift Package Manager

  • It is the “official” package manager for Swift, so its support is about as solid as we can get.
  • Swift Package Manager is a single cross-platform for building, running, testing, and packaging our swift code.
  • Configuration of packages is written in Swift itself, making it easy to configure targets, declare products and manage package dependencies.
  • Swift Package Manager organizes code into modules.
  • Each module specifies a namespace and enforces access controls on which parts of that code can be used outside of the module.

Read to understand the µFeatures Architecture

Splitting projects into multiple small modules using local packages/dependencies.

Let’s say we have a project called ModularWithSPM. Make sure we add/create an explicit folder/directory called ‘Packages’.

NOTE: We can choose the name for this folder/directory.

We have a Packages folder now :)
  1. Create a New -> Package…
Create new package

2. Navigate to the folder/directory ‘Packages’ or other which we have created.

3. Name the Package as ‘Common’

4. It will open a new Xcode instance with the Package -> Common as shown in follow.

5. Let’s add the supported platforms with supported targets.

NOTE: We all can read the Package.swift file and understand other configurations as per our own space. 

NOTE: We can close the Xcode Instance of Common Package project.

6. Go to the ModularWithSPM project. Right-click on the Project file and click on Add Packages…

7. Click on Add Local

8. Add the Common package. (NOTE: We might need to navigate to the Package folder)

Select Common package and click on Add Package button.

9. Our Project Navigator will look like below.

10. Add the Common Package

Go To Targets -> Build Phases -> Link Binary With Libraries

Select Common -> Add Button

11. Now feel free to, Import Common Package and use it as we want.

Follow, Step 1 to Step 11 keep adding more packages into project.

i.e., Network, Favourites, Home, Logger, Login, Registration, and etc.

Conclusion:

These are a handful of steps. This is a fairly basic yet powerful guide. At a very high level what we get to motivate all of us to begin with.

1. Modular project structure

Module driven project structure

2. Write the test cases to the individual to the package.

Module Test Cases

3. Have a feature-specific storyboard.

Module storyboard

4. Have a feature-specific Assets Catalog.

Module Assets

5. Sharing the module

You can easily drag the Package into any other project right away.

Go To Targets -> Build Phases -> Link Binary With Libraries

import module and use it.

Everything works!!!

Once we understand the importance of modular design and start with a small step to begin with we can achieve greater heights for sure!!!

Don't limit modularity for project structure only. Understand the advantages of modular architecture and apply it for functional aspect too and see the benefits you get.

What next?

How to cache the local packages/dependencies?

Must Read:

If you like the article then do….

--

--

Santosh Botre

Take your time to learn before develop, examine to make it better, and eventually blog your learnings.