返回首页

Swift Package Manager Series 07|SPM management method in medium-sized iOS projects

What medium-sized projects are really afraid of is that modules exist but do not have stable dependency directions and responsibility boundaries.

If I were to use SPM to manage a medium-sized iOS project, my first concern would not be “how many packages to remove”, but these three questions:

  • Which abilities are really worthy of independence?
  • How to maintain stable direction of module dependencies
  • What should be retained in the host project and what should not be retained?

Because medium-sized projects are most likely to fall into a trap: It seems that modularization has begun, but in fact it is just a redistribution of the complexity in the original main project to multiple packages.

So what I want to talk about in this article is how I judge modules, hierarchies and dependency graphs.

1. I will not pursue “more modules” from the beginning, but will first pursue “clear levels”

The complexity of medium-sized projects is usually not large enough to require extreme subdivision, but it is enough that “all in the main project” starts to become dangerous.

The most important thing at this time is to remove the layering first.

I usually first see if the following categories of things can be stably separated into the project:

  • Basic ability layer
  • Domain capability layer
  • UI reuse layer
  • Host project layer

Once these four types of things are mixed together, it is easy for the project to get out of control as soon as the scale increases. But if the hierarchy is established first, the number of modules will be a later detail.

2. I will first divide the core modules into three categories:

1. Basic ability module

For example:

  • network
  • Log
  • cache
  • Configuration reading
  • Basic tools

The characteristics of this type of module are that it is far away from the business, has strong reusability, and the dependency direction should be closed as far as possible.

2. Domain capability module

For example:

-Account

  • User
  • Content
  • Order

These modules are business capability centers. They should host domain models, warehouses, use cases, rather than specific page implementations.

3. UI reuse module

For example:

  • Design system
  • Common components
  • Universal list container

I will be very careful here to avoid accidentally splitting the business page into UI modules. UI reuse modules are more suitable for carrying stable, universal, and cross-page component capabilities.

3. What should be retained in the host project?

This is an issue that many teams tend to overlook.

Once you start doing SPM, it is easy to have a tendency: “Since they are all modular, it is best for the host project to be as thin as possible.”

This statement is only half true.

The host project really shouldn’t carry too many reusable capabilities, but it should still retain some things that naturally belong to the host, such as:

  • App life cycle orchestration
  • Routing assembly
  • Environment configuration injection
  • Module assembly
  • Codes related to final product form

In other words, the host project should focus on assembly and product-level collaboration, rather than carrying a bunch of capabilities that could have been sunk.

4. I won’t dismantle it too finely at the beginning.

This is something I insist on very much.

One of the pitfalls that medium-sized projects are most likely to fall into is “modularization for the sake of modularity”, which ends up tearing the system apart too much.

Once the module is too fragmented, problems will appear immediately:

  • Complex dependency graph
  • The debugging path becomes longer
  • Frequent jumps across modules during review
  • A little change involves multiple package linkages

This can quickly lead teams to doubt modularity itself.

So I prefer:

  • First dismantle a few large modules with clear responsibilities
  • observe several iterations
  • Decide whether to refine

Choosing the system very finely the first time is usually done in a hurry.

5. Dependency direction is more important than the number of modules

If I were asked to choose between “removing more modules” and “straightening out the dependencies”, I would definitely choose the latter.

Because more modules does not automatically equal a better structure. What really determines whether the system can evolve stably in the long term is whether the direction of dependence is clear.

For example, I care more about whether these relationships hold:

-The base layer does not depend on the business layer

  • The domain layer does not rely on the host layer in reverse
  • The UI reuse layer does not steal the business semantics of the page
  • The host layer is responsible for assembly, rather than holding all the internal implementation in its hands

As long as the dependency directions are messed up and no matter how many modules there are, the system will only be “multi-layered nested coupling”.

6. I will be very wary of “universal public modules”

This is an anti-pattern that appears frequently in medium-sized projects.

When a project is modularized at the beginning, there will often be a question called:

  • Common
  • Shared
  • Core
  • Base

Super modules like this.

If this module carries clear basic capabilities, then there is no problem. But the “public modules” in many projects will eventually become:

  • Can be relied on anywhere
  • Put everything in there
  • There are both tool functions, business models, and UI components

The result is that it becomes the new central coupling point.

So I prefer to split it into small basic modules with clear responsibilities, rather than building a large public module that covers everything.

7. The most important thing for modularization of medium-sized projects is consistent team cognition.

This is very realistic.

In medium-sized projects, many structural problems are caused by the team not having a consistent understanding of boundaries. For example, some people think:

  • Everything related to the page is considered a module

Some people think:

  • Domain models should be disassembled separately

Some people think:

  • Public components should be placed together with business modules for more convenience

If these cognitions are not unified for a long time, the system will continue to grow boundary conflicts even with SPM.

So in medium-sized projects, I will attach great importance to:

  • Is the naming of module responsibilities consistent?
  • Is there a consensus on the dependency direction?
  • When adding new code, can you tell which layer it should be placed on?

This is much more important than simply “how many packages were opened.”

8. Conclusion: The core of using SPM to manage medium-sized projects is not the quantity, but the long-term stability of the dependency graph.

To put it in shorter form, I would say:

When using SPM to manage a medium-sized iOS project, the most important thing is to form a long-term stable dependency direction between basic capabilities, domain capabilities, UI reuse and host assembly.

By doing this, the number of modules will naturally find the right size. If you can’t do this, no matter how much you split it, it will just re-slice the complexity.

FAQ

读完之后,下一步看什么

如果还想继续了解,可以从下面几个方向接着读。

Related

继续阅读

这里整理了同分类、同标签或同类问题的文章。