Modular Apps with a Tuist — Part 2 — Network Module

A step-by-step code walkthrough converting an existing app to a modularised app using tuist.

Note that this article will only really make sense if you follow each step along the way by looking at the commits in this repo. Clone the project and use SourceTree or similar on the PartTwo_NetworkingRefactor branch. Most of the commits are linked in this text.

A Bit of Style

As it happens tuist supports a lint command, with 2 main options “code | project”. The code parameter will lint all targets, but a target can be specified like so:

tuist lint code Pokedex

Running the project lint is fine without any issues. Linting the source code however, not so much. The original project uses a Swiftlint YML file and this is in the root of the repo. The tuist lint command doesn’t have an option to specify the configuration file but it does pick it up if it is located in the root of the tuist project. Without the configuration file the lint gives 253 violations, 2 serious. Copying over the YML file and fortunately it is a much more reasonable 0.

But of course the core idea is that the linting is run every time you run a build — it needs to be a build phase like before. I add a few lines of bash to scripts/, give it execution permission, and then (tuist edit) update the makeAppTargets with:

actions: [        "../scripts/",
name: "SwiftLint")

Opening the project again and selecting the build phases now shows SwiftLint. Job done.

Xcode build phase showing the syntax for calling swiftlint
Xcode build phase showing the syntax for calling swiftlint

Back to the refactor.

Splitting Layers

An aside here is that there is a different approach where frameworks can be added to the main tuist project but that involves a bit more preliminary work configuring scaffold templates, and I will go through this process in a future article.

Next, I move the Services folder to the NetworkKit sources folder. The Network app target is there to validate the NetworkKit framework and will consist of a simple view controller and connects to the network kit code to make the API call. The NetworkUI target is not needed, and can be deleted. The project definition needs to be updated to remove this dependency, and then extended support a packages parameter in the same way that Pokedex was updated, as well as several changes done to the project template. The packages Moya and Result are added to the framework target. When I run the compile I see that both Configuration and Constants are required so these 2 are copied over. After that is done, then there is just one small fix required for Swift 5.3 — update keyword for the protocol as ‘class’ is deprecated.

At this point the NetworkKit framework builds, so I move over the existing test case “testEndpointReturnsData”. When code is in a framework and needs to be accessed outside that framework then it is possible to remove the @testable in the import statement for the tests since it should be defined as public anyway.

The next task is to use it in the Network example App. Here I add a SimpleViewController that contains a label, textfield and button whose action method triggers the search, which is implemented in the DataProvider class. The DataProvider instance imports the NetworkKit and makes the call to the API, with the response triggering a call on the notifier instance, which is a protocol implemented by the view controller, and completes the cycle. I copied over the image assets and updated the launch screen for completeness.

Rewiring The Machine

Now that the coding changes are done tuist has a nice tool to visualise how it all comes together: graph.

The Network module looks like this:

And then the Pokedex module looks like this:

That completes the tasks for this article. In the next article I will go through the process of separating out the UI layers.

If you find this useful, please follow to get the next updates.

The completed code for this article is here.

iOS Software developer and electronic music fan

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store