How one can plan a migration to Swift 6 – Donny Wals

How one can plan a migration to Swift 6 – Donny Wals


Swift 6 has been accessible to us for the higher a part of a yr now, and an increasing number of groups are contemplating or taking a look at migrating to the Swift 6 language mode. This sometimes entails making an attempt to activate the language mode or turning on strict concurrency, seeing an entire bunch of warnings or errors, after which deciding that in the present day will not be the day to proceed with this migration.

In the present day I wish to suggest an method to how one can plan your migration in a method that gained’t scare you out of making an attempt the migration earlier than you’ve even began.

Earlier than you undergo this whole put up anticipating me to let you know how one can go to Swift 6 inside a matter of days or perhaps weeks, I am afraid I’ll must disappoint you.

Migrating to Swift 6, for lots of apps, goes to be a really sluggish and prolonged course of and it is actually a course of that you do not need to rush.

Taking an preliminary stock

Earlier than you begin to migrate your codebase, I’d extremely suggest that you simply take stock of the state of your codebase. Because of this it is best to check out how modularized your codebase is, which dependencies you might have in your codebase, and perhaps most significantly how a lot concurrency you’re actually utilizing proper now. Learn how usually you’re explicitly, and purposefully you’re leaving the principle thread. And attempt to perceive how a lot of your code will run on the principle thread.

You also needs to take a look at your group and determine how up-to-date your group is, how comfy they’re with Swift concurrency already. Ultimately, your complete group will want to have the ability to work on and along with your Swift 6 codebase.

On a code stage, it is important to grasp how a lot concurrency you really want as a result of Swift concurrency is, by design, going to introduce quite a lot of concurrency into your app the place perhaps you do not really want all of that concurrency. That’s why it’s so vital so that you can determine the quantity of concurrency you’ll require beforehand by analyzing what you might have now.

For instance, if in case you have a view and you’ve got a view mannequin, and that view mannequin talks to a different layer, then most likely you might be doing many of the work on the principle thread proper now.

When you hit your networking layer, your community calls will run someplace else, and when your networking associated features invoke their callbacks, these will sometimes run on a background thread, and then you definitely come again to the principle thread to replace your UI.

On this state of affairs, you do not want quite a lot of concurrency; the truth is, I’d say that you do not want concurrency past what URLSession gives in any respect. So when you’re adopting Swift Concurrency, you’ll need to perceive how one can construction your code to not depart the principle thread for each async name.

You would possibly have already got adopted async-await, and that is utterly advantageous—it most likely implies that you do have extra concurrency than you really want. Each nonisolated async operate that you simply write will, by default, run on a background thread. You don’t at all times want this; you’ll more than likely need to explicitly isolate a few of your work to the principle actor to forestall leveraging concurrency in locations the place it’s merely not benefitting you.

You may additionally need to just be sure you perceive how dependent or how coupled your codebase is as a result of the extra coupling you might have and the much less abstractions and modularization you might have, the extra complexities you would possibly run into. Understanding your codebase deeply is a prerequisite to shifting to Swift 6.

When you perceive your codebase, you would possibly need to take a look at modularizing. I’d say that is the best choice. It does make migrating a bit bit simpler.

So let’s speak about modularization subsequent.

Modularizing your codebase

Once you migrate to Swift 6, you may discover that quite a lot of objects in your code are being handed from one place to a different, and whenever you begin to introduce concurrency in a single a part of the code, you’re basically compelled emigrate something that depends upon that a part of your codebase.

Having a modularized codebase means you could take your codebase and migrate it over time. You may transfer part by part, somewhat than being compelled to maneuver every thing unexpectedly.

You should use options like @preconcurrency to be sure that your app can nonetheless use your Swift 6 modules with out working into every kind of isolation or sendability warnings till your app additionally opts in to strict concurrency.

In the event you do not need to modularize your codebase otherwise you really feel your codebase is method too small to be modularized, that is utterly advantageous. I am simply saying that the smaller your parts are, the better your migration goes to be.

As soon as the state your codebase is in and you’re feeling comfy with how every thing is, it is time to activate strict concurrency checks.

Turning on strict concurrency checks

Earlier than you activate Swift 6 language mode, it is strongly recommended to activate strict concurrency checking for the modules that you simply need to migrate. You are able to do this for each SPM and in Xcode on your app goal.

I’d suggest to do that on a module by module foundation.

So if you wish to refactor your fashions bundle first, activate strict concurrency checks on your mannequin bundle, however not but on your app. Turning on strict concurrency for just one module means that you can work on that bundle with out forcing your app to decide into all the sendability and isolation checks associated to the bundle you’re refactoring.

Having the ability to migrate one bundle at a time is tremendous helpful as a result of it makes every thing lots simpler to purpose about because you’re reasoning about smaller bits of your code.

After you have your strict concurrency checks turned on you are going to see an entire bunch of warnings for the packages and targets the place you have enabled strict concurrency and you can begin fixing them. For instance, it’s doubtless that you will run into points like most important actor remoted objects to sendable closures.

You may need to just be sure you perceive these errors earlier than you proceed.

You need to be sure that your entire warnings are resolved earlier than you activate Swift 6 language mode, and also you need to just be sure you’ve received a extremely good sense of how your code is meant to work.

The toughest half in fixing your strict concurrency warnings is that making the compiler glad generally simply is not sufficient. You may incessantly need to just be sure you truly purpose concerning the intent of your code somewhat than simply making the compiler glad.

Think about the next code instance:

func loadPages() {
  for web page in 0..<10 {
    loadPage(web page) { lead to 
      // use end result
    }
  }
}

We’re iterating over a listing of numbers and we’re making a bunch of community calls. These community calls occur concurrently and our operate does not watch for all of them to finish. Now, the quickest option to migrate this over to Swift concurrency may be to jot down an async operate and a for loop that appears like this:

func loadPages() async throws {
  for web page in 0..<10 {
    let end result = strive await loadPage(web page)
    // use end result
  }
}

The which means of this code has now modified fully. We’re making community calls one after the other and the operate does not return till each name is full. If we do need to introduce Swift concurrency right here and preserve the identical semantics we must create unstructured duties for each single community name or we may use a process group and kick off all our community calls in parallel that method.

Utilizing a process group would change the way in which this operate works, as a result of the operate must watch for the duty group to finish somewhat than simply letting unstructured duties run. On this refactor, it’s essential to grasp what structured concurrency is and when it is sensible to create unstructured duties.

You are having to consider what the intent of the code is earlier than you migrate after which additionally how and if you wish to change that in your migration. If you wish to preserve every thing the identical, it is usually not sufficient to maintain the compiler glad.

Whereas instructing Groups about Swift Concurrency, I discovered it actually vital to know precisely which instruments you might have on the market and to consider how you ought to be reasoning about your code.

As soon as you have turned on Swift Concurrency checks, it is time to be sure that your complete group is aware of what to do.

Guaranteeing your group has all of the information they want

I’ve seen a number of corporations try migrations to SwiftUI, Swift Knowledge, and Swift Concurrency. They usually take approaches the place a small group does all of the legwork by way of exploring and studying these applied sciences earlier than the remainder of the group is requested to study them too and to undertake them. Nevertheless, this usually means that there is a small group within the corporate that you might think about to be specialists. They will have had entry to assets, they’re going to have had time to coach, and as soon as they provide you with the overall massive image of how issues ought to be performed, the remainder of the group sort of has to study on the job. Generally this works nicely, however usually this breaks down as a result of the remainder of the group merely wants to completely perceive what they’re coping with earlier than they will successfully study.

So I at all times suggest if you wish to migrate over to Swift Concurrency have your group enroll in one in all my workshops or use my books or my course or discover every other useful resource that may train the group every thing they should know. It is actually not trivial to select up Swift Concurrency, particularly not if you wish to go into strict concurrency mode. Writing async-await features is comparatively simple, however understanding what occurs is actually what you want if you happen to’re planning emigrate and go all-in on concurrency.

As soon as you have determined that you’re going to go for Swift 6 and did you need to stage up your group’s concurrency expertise ensure you truly give all people on the group an opportunity to correctly study!

Migrating from the skin in

As soon as you have began refactoring your packages and it is time to begin working in your app goal I discovered that it actually is sensible emigrate from the skin in. You would additionally work from the within out and in the long run, it actually depends upon the place you need to begin. That stated, I usually like to begin within the view layer as soon as all of the back-end stuff is finished as a result of it helps me decide at which level within the app I need to depart the principle actor (or when yo apply a most important actor annotation to remain on the principle actor).

For instance, if you happen to’re utilizing MVVM and you’ve got a view mannequin that holds a bunch of features, the place ought to these features run?

That is the place the work that you simply did up entrance comes into play since you already know that within the previous method of doing issues the view mannequin would run its features on the principle thread. I’d extremely suggest that you don’t change this. In case your view mannequin used to run on the principle thread which is just about commonplace, preserve it that method.

You may need to apply a most important actor annotation to your view mannequin class.

This isn’t a nasty factor by any means, it isn’t a hack both. It is a method so that you can make sure that you are not switching isolation contexts on a regular basis. You actually do not want a ton of concurrency in your app code.

Apple is even contemplating introducing some language mode for Swift the place every thing goes to be on the principle actor by default.

So so that you can default your view fashions and perhaps another objects in your code base to the principle actor merely makes quite a lot of sense. When you begin migrating like this you may determine that you simply actually did not want that a lot concurrency which you already ought to know as a result of that is what you discovered early on into course of.

That is additionally the place you begin to encounter warnings which might be associated to sendability and isolation contexts. When you begin to see these warnings and errors, you determine that the mannequin ought to or should not be sendable relying on whether or not the change of isolation context that’s inflicting the warning is predicted.

You may resolve sendability issues with actors. That stated, making issues actors is normally not what you are in search of particularly when it is associated to fashions.

Nevertheless, whenever you’re coping with a reference kind that has mutable state, that is the place you would possibly introduce actors. It’s all about determining whether or not you have been anticipating to make use of that kind in a number of isolation contexts.

Having to deeply purpose about each error and warning can generally really feel tedious as a result of it actually slows you down. You may simply make one thing sendable, you might simply make one thing an actor, and it would not impression your code that a lot. However you might be introducing quite a lot of complexity into your codebase whenever you’re introducing isolation contexts and whenever you’re introducing concurrency.

So once more, you actually need to just be sure you restrict the quantity of concurrency in your app. You sometimes do not want quite a lot of concurrency inside an software. I can not stress this sufficient.

Pitfalls, caveats, and risks

Migrating to Swift 6 positively comes with its risks and uncertainties. In the event you’re migrating every thing unexpectedly, you are going to be embarking on an enormous refactor that may contain touching nearly each single object in your code. In the event you introduce actors the place they actually should not belong, you all of the sudden have every thing in your code changing into concurrent as a result of interacting with actors is an asynchronous proces.

In the event you did not observe the steps on this weblog put up, you are most likely going to have asynchronous features everywhere, and so they may be members of lessons or your view or anything. A few of your async features are going to be remoted to the principle actor, however most of them will likely be non-isolated by default, which implies that they will run wherever. This additionally implies that if you happen to go fashions or objects out of your view to your few mannequin to another place that you simply’re skipping isolation contexts on a regular basis. Generally that is utterly advantageous, and the compiler will determine that issues are literally secure, however in quite a lot of circumstances, the compiler goes to complain about this, and you can be very pissed off about this as a result of you haven’t any concept what’s improper.

There’s additionally the matter of interacting with Apple’s code. Not all of Apple’s code is essentially Swift 6 suitable or Swift 6 pleasant. So that you would possibly end up having to jot down workarounds for interacting with issues like a CLLocationManagerDelegate or different objects that come from Apple’s frameworks. Generally it is trivial to know what to do when you absolutely perceive how isolation works, however quite a lot of the occasions you are going to be left guessing about what makes probably the most sense.

That is merely unavoidable, and we want Apple to work on their code and their annotations to be sure that we are able to undertake Swift 6 with full confidence.

On the identical time, Apple is taking a look at Swift as a language and determining that Swift 6 is actually not within the place the place they need it to be for normal adoption.

In the event you’re adopting Swift 6 proper now, there are some issues which may change down the road. You need to be prepared to take care of that. In the event you’re not prepared to take care of that, I’d suggest that you simply go for strict concurrency and do not go all-in on Swift 6 as a result of issues would possibly change down the road and you do not need to be doing a ton of labor that seems to be out of date. A pair variations of Swift down the road, and we’re most likely speaking months, not years, earlier than this occurs.

In Abstract

Total, I feel adopting Swift 6 is a large enterprise for many groups. If you have not began already and also you’re about to begin now, I’d urge you to take it sluggish – take it simple and just be sure you perceive what you are doing as a lot as potential each step of the way in which.

Swift concurrency is fairly difficult, and Apple continues to be actively engaged on enhancing and altering it as a result of they’re nonetheless studying about issues which might be inflicting issues for folks on a regular basis. So for that purpose, I am not even positive that migrating to Swift 6 ought to be one in all your main objectives at this cut-off date.

Understanding every thing round Swift 6 I feel is extraordinarily helpful as a result of it does make it easier to to jot down higher and safer code. Nevertheless, I do consider that sticking with the Swift 5 language mode and going for strict concurrency might be your most secure guess as a result of it means that you can write code that might not be absolutely Swift 6 compliant however works utterly advantageous (at the least you’ll be able to nonetheless compile your mission even if in case you have an entire bunch of warnings).

I’d like to know your ideas and progress on migrating to Swift 6. In my workshops I at all times hear actually cool tales about corporations which might be engaged on their migration and so if in case you have tales about your migration and your journey with Swift 6, I’d love to listen to that.

Leave a Reply

Your email address will not be published. Required fields are marked *