Xcode, Modularised. — Part 1

Hamoon Jamshidi Meydandar
The Startup
Published in
6 min readAug 16, 2020
A Harry Potter Quidditch miniature made by LEGO
LEGO was a good start for thinking with Modular in mind.

What is modularising?

When we use “import something,” we say to our beautiful Mac, that connect the code in this particular file to that something. When we make any app, we use lots and lots of modules — most of them we don’t even see. Why is it good?

It can help us and our machine. We can collaborate better on the code, re-use the code, and help Xcode to build faster.

How?

By separating concerns.

Separation of Concerns

Beloved MagSafe (2006–2016)

You connect your Mac’s charger to the power outlet. Your Mac has no idea if there is a power outlet, let alone knowing how to convert 220V AC to a 16.5 V DC! That is the charger’s job. Your Mac just knows how to tell the charger how much power it needs, and how to receive the power.
And the charger doesn’t know how Mac works. It just knows how to talk to it about its power needs. And it also doesn’t know where the power is coming from, is it wind power, nuclear, or some nature unfriendly, terrible thing, like solar — not joking, if you want to save the planet and humans, go nuclear! Wind power and marine currents are not bad, either.

Anyways…

This is good, because when building Mac, it is simpler to build the Mac and not the power converting.

And if the charger is faulty, you won’t have to change your Mac. Luckily! I’m happy they haven’t soldered a power plant to the Logic Board!

This is analogous to modular programming; Each module can be built separately, tested separately, and used in many different places. It can be replaced easily, as well.

Before making a module, it is crucial to understand how to make modules simple.

Being simple is a process. At each moment, you should ask:

Is this essential? Does it make it more understandable?

If no, cut it.

A few questions that will help you in making the module, simple:

What is the task of this module?

Before doing anything — even naming your module — define the task it is.

Define the input and output. Also, define what other changes it will make outside of the module.

Can I make divide this module into two or more independent, testable modules?

This one can be tricky.

We should always try to make the modules smaller, but the module should be able to work and get tested without depending on a particular module.
Of course, modules can import other modules, but they should be able to work fine if we replace the modules — read more on Protocol Oriented Programming.

Again, your MacBook depends on the charger, but not a particular charger. Any charger that matches the requirements is fine.

Now here in my module, I could have also added the ability to crop the photos. But then I asked “can they be divided into two, work fine and be testable without depending on another?” and the answer was yes.

A cropping module and a photo picker do not care about each other — they need a photo to be passed to/from — and can be tested separately.

But if I would try to divide this module even further, whatever the results, they will always need each other to work, or even be tested.

What are the essential inputs and outputs

My photo picker can have many inputs — for example, the number of photos, or size.
But the essential input is just asking for photos ( any number).
I can extend on this, add options such as specifying the number of photos, and size, etc.
The essential output will be a set of photos.

Let’s get to work now!

To build a new module, I prefer to add a new Project into my Workspace.

For that, you go to New>Project… and choose Frameworks and give it a name. ( Optional: choose to include tests. Tests will help you a lot in building a large, modular project)

IMPORTANT: You must choose your Workspace in both “Add to” and “Group”

Now your Workspace should look like this ( the Pods are optional )

So, now that I know the minimum input and output for my module, let’s see the requirements. What frameworks it will be built upon, and what do they need.

I want to start with only the “PhotosUI” framework built by Apple.
This framework returns a ViewController to show the photo picking, and it will return the results to the delegate object we have provided to.

So, now I know the requirements:

  1. One object. It will conform to PhotosUI’s delegate protocol
  2. A method that will return a ViewController
  3. A method that will return the final value, or an Error

So first I start with the simplest possible way:

I don’t want to go to details of implementing PhotosUI, there are many available out there. I want to focus on how to make a useful and simple module.

Now we should test to see if this part of the module is working fine.
There are many ways to test a code and a module. Since this code needs iOS photo library, we will need to test it on an iOS device/simulator.

For that, I prefer to add a Target to the module: New>Target>App.
Here we will have a full iOS app that is only inside our module and separated from the workspace. We can dedicate it to test this module.

You will see the Target in Targets.
I named it “ImagePickerDemo”.

To use the code inside the framework, mark it as public or open. Just like how I did with the “ImagePicker” class.
Public means that you can access it from outside of the module, by importing the module — import <module’s name> — and open means you can access a class, but also you can subclass it, or override the methods, etc.

I go with the public. In fact, I give the least possible access for module to be used properly.

Setting the least possible access, makes it more predictable and simpler to use.

Adding options.

Now that we have tested the core functionality, we can add the options that we will need in our project.

For example, I will need to set the maximum number of photos I receive.
I can set those as options, for example:

pickPhotos(type: MediaTypes? = nil, limit : Int = 0)

I already set a default values, because the module doesn’t necessarily need those data from other modules to work properly.

That’s all for today.

Let me know what you think. You can always find me on Twitter, or Instagram.

--

--

Hamoon Jamshidi Meydandar
The Startup

Trying to understand myself, universe and reach my wild dreams. Find me @Hamoonist